Click an Ad

If you find this blog helpful, please support me by clicking an ad!

Friday, June 28, 2013

Running a Powershell Script on a Remote Computer From a Local Powershell Script

Let me tell you about why I needed this:

I will preface this by saying that I cite a use case which includes Veeam, but it's just an app that creates files, and your use case could include other files.

I have a server named FileServerPROD that serves as my Veeam Repository. At the end of my backup job, I have a robocopy process that synchronizes all of the files on FileServerPROD with FileServerDR at another site. These copy jobs take several hours at night, and an analysis posed the question, "What if something bad happens in the middle of the robocopy job?"

The answer is "Your offiste backup copies are toast, that's what." Uh.... unacceptable.

I came up with a process that creates a "Yesterday" folder and creates a copy of the backup files BEFORE my robocopy process starts its thing. This way, I keep a copy of my old files that is untainted should the robocopy go south. The problem I encountered was that if I tried to do this from my side of the WAN, the copied files would have to come all the way to the computer that the copy was initiated from (across the WAN) and then BACK to the destination - across the WAN again! I needed to initialize the copy operations from FileServerDR so the data would all stay local (and speedy).

Powershell isn't designed to easily launch Powershell scripts remotely from inside of other Powershell scripts. Obviously, the ability would be a security concern. So I cobbled together this workaround.

First off, here's the script that runs at the end of the Veeam job and lives on FileServerPROD, which I will dissect below. I've made the most pertinent code red:



$starttime = ((Get-Date)|out-string)

#Execute Remote Powershell script to move the current backup files into a "Yesterday" folder and make new copies to run the mirror operation on
$Server="FileServerDR"
$process=[WMICLASS]"\\$Server\ROOT\CIMV2:win32_process"
$result=$process.Create("powershell.exe -File C:\ps\Daily-Apps.ps1")
$ProcessID = $result.processID

#Make sure the process has finished running its course before initiating the robocopy job

#Only when the process initiated above completes while $Running be $null, and the loop end
$Running = 1
While ($Running -ne $null){
Start-Sleep -seconds 60 #wait 1 minutes
$Running = (get-process -id $ProcessID -ComputerName $Server -ea 0) #Check the process again
}

$YesterdayCreated = ((Get-Date)|out-string)
#The section below copies the Veeam Jobs, and then sends a report
start-process "c:\robocopy.exe" -ArgumentList 'R:\Backups\Daily-Apps \\FileServerDR\R$\Daily-Apps /MIR /R:1 /W:5 /NP /LOG:C:\Logs\VeeamRobocopy-Daily-Apps.log' -wait

$endtime = ((Get-Date)|out-string)
$To = "me@contoso.com"
$From = "administrator@contoso.com"
$Body = (("Start Time: $starttime")+("Yesterday Folder Created: $YesterdayCreated")+("End Time: $endtime"))
$Subject = "Robocopy Offsite - Veeam Daily-Apps - Job Results"
$SMTPServer = "SMTPServer.contoso.com"
$Attachment = "C:\Logs\VeeamRobocopy-Daily-Apps.log"
Send-Mailmessage -to $To -Subject $subject -From $From -body $body -smtpserver $SMTPServer -attachments $Attachment



And here's the script that runs on FileServerDR:



#Remove the current "Yesterday" folder
remove-Item R:\Daily-Apps-Yesterday -Recurse -Force -ea 0

#Create New Folder
mkdir R:\Daily-Apps-Yesterday

#Copy contents of the old folder to the new folder
copy-Item R:\Daily-Apps\*.* R:\Daily-Apps-Yesterday



Now, let's go through the FileServerPROD script:

$starttime = ((Get-Date)|out-string)
This gets a time marker for information purposes.

#Execute Remote Powershell script to move the current backup files into a "Yesterday" folder and make new copies to run the mirror operation on
$Server="FileServerDR"
$process=[WMICLASS]"\\$Server\ROOT\CIMV2:win32_process"
$result=$process.Create("powershell.exe -File C:\ps\Daily-Apps.ps1")
$ProcessID = $result.processID
The code above launches a Powershell process on CITYFPDR which runs the script remotely. The last line gets the process ID, which we will use next.

#Make sure the process has finished running its course before initiating the robocopy job
#Only when the process initiated above completes while $Running be $null, and the loop end
$Running = 1
While ($Running -ne $null){
Start-Sleep -seconds 60 #wait 1 minutes
$Running = (get-process -id $ProcessID -ComputerName $Server -ea 0) #Check the process again
}
THIS IS THE KEY! This While loop puts the script on pause until the remote script finishes by checking if the process ID exists. If the ProcessID doesn't exist (is finished) the the get-process query will return $null, thus ending the loop.

$YesterdayCreated = ((Get-Date)|out-string)
#The section below copies the Veeam Jobs, and then sends a report
start-process "c:\robocopy.exe" -ArgumentList 'R:\Backups\Daily-Apps \\FileServerDR\R$\Daily-Apps /MIR /R:1 /W:5 /NP /LOG:C:\Logs\VeeamRobocopy-Daily-Apps.log' -wait
Here we get another time marker and the script starts the robocopy job.

$endtime = ((Get-Date)|out-string)
$To = "me@contoso.com"
$From = "administrator@contoso.com"
$Body = (("Start Time: $starttime")+("Yesterday Folder Created: $YesterdayCreated")+("End Time: $endtime"))
$Subject = "Robocopy Offsite - Veeam Daily-Apps - Job Results"
$SMTPServer = "SMTPServer.contoso.com"
$Attachment = "C:\Logs\VeeamRobocopy-Daily-Apps.log"
Send-Mailmessage -to $To -Subject $subject -From $From -body $body -smtpserver $SMTPServer -attachments $Attachment
And here we get an "end time" marker, then an email is sent with all of the time markers we've gathered along with the robocopy log as an attachment.




Here's the dissection of the script that runs on the other side, creating that "Yesterday" folder and a safe copy of my data:

#Remove the current "Yesterday" folder
remove-Item R:\Daily-Apps-Yesterday -Recurse -Force -ea 0
This resets the yesterday folder

#Create New Folder
mkdir R:\Daily-Apps-Yesterday
This makes a new yesterday folder

#Copy contents of the old folder to the new folder
copy-Item R:\Daily-Apps\*.* R:\Daily-Apps-Yesterday
Like it says, this copies the contents over

Monday, June 24, 2013

Automated WSUS Report - Computers in the Unassigned Computers Container

It seems like one of the other admins is always adding a computer to the domain and not telling me, and I realized that I need to make it a priority to check the "Unassigned Computers" container every so often to ensure there isn't anything in it. This is the sort of thing Powershell shines at!

Before you run this, make sure you have a C:\Temp folder, or change the output file path. I did my explanation in the comments within the script below:



$WsusServer = "WSUSServer.contoso.com"
$UseSSL = $false
$PortNumber = 80
$TempFile = "C:\Temp\Output.txt"

#E-mail Configuration
$SMTPServer = "SMTPServer.contoso.com"
$From = "administrator@contoso.com"
$To = "me@contoso.com"
$Subject = "PS Report - Unassigned Computers in WSUS"

#Connect to the WSUS 3.0 interface.
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
$Wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$UseSSL,$PortNumber);

#Get the FQDN of computers that reside in the Unassigned Computers container
$Unassigned = (($Wsus.GetComputerTargetGroups() | ?{$_.Name -eq 'Unassigned Computers'}).GetComputerTargets() | select FullDomainName)

#Output each to the temp file
Foreach ($Computer in $Unassigned){
($Computer.FullDomainName) | out-string | add-content $TempFile
}

#Create the body of the email, inserting <BR> tags between each line.
$Body = (Get-Content $TempFile) -join '<BR>'

#If there are computers in the unassigned computers group, send me an email listing them
If ($Unassigned -ne $null){
Send-Mailmessage -From $From -To $To -Subject $Subject -SMTPServer $SMTPServer -Body $Body -BodyAsHTML
}

#Delete the temp file
Remove-Item $TempFile -ea silent



One of the challenges I faced here was getting the computer names into the text file. Out-String didn't work because of the type of object the $Unassigned was, for some reason. I ended up outputting to the temp file, then using -join to put in <BR> tags, then sending the email with the BodyAsHTML option. In HTML, the <BR> tag just represents a carriage return (go to the next line).

Friday, June 21, 2013

Grep for Windows - What a Welcome Tool!

Last week we renamed a file server, and I needed to dig through all of my Powershell scripts and change the name wherever it was referenced. What a tedious chore!

Oh how I wished there was a tool that would search inside of multiple text files and tell me where a string of text appears!

THERE IS! 

It's called Grep for Windows, and it is awesome. It's wizard driven and will even search based on regular expressions.


Wednesday, June 19, 2013

Windows 8 - Mini-Review, and My Ability to Switch Users went Missing!

I'll get to the actual fix towards the bottom, but let me diverge into my mini-review of Windows 8 for a couple of paragraphs first.

This weekend I took the plunge and installed Windows 8 on my home desktop. I took full advantage of that promo that Microsoft had back in January and picked up Windows 8 for $30. I still think Windows 8 is a "failure" for the business segment due to so many business users being, well, fairly clueless when it comes to technology. I also have come to believe that humanity in general despises change and lacks a yearning to learn new things, especially when the old way "works just fine". Okay, enough sociology.

I've been using Windows 8 for a few days now, and let me tell you: It has some great features! While the switch to the Metro interface (Start Screen) is jarring, I like that I have big buttons for my most used apps. One of the fixes in 8.1 is that you can make the wallpaper on your Start Screen the same as your desktop wallpaper, so that should help. The live tiles are less useful on a desktop, but I can see their allure. Some of the built in apps are pretty barebones, but there's a store and I can get more apps. The first thing I found was TuneIn, which lets me listen to terrestrial radio stations from all over the planet - awesome! Half the time when I hit the start button on my keyboard I am typing the thing that I want to open anyway, so my use of the start screen is fairly limited. One thing I overlooked about the big buttons is the ability to "remind" myself that I need to do something, like check my torrents, for instance. When I press start now there's my big green uTorrent button staring at me.

The second thing that I really like is the parental control. I have a 12 year old, and now I can look at where he's going on the web independent on whether he figures out how to clear his history. I hear you now: "But why don't you just set up a Squid proxy or something - you're a geek!" This is an option I have thought of many times, but I don't want to pay the electric bill and deal with the management (at home, no less) of yet another system. I also have him locked down with an application whitelist, so that he can only run things I say that he can ahead of time. The cherry on top is that I can specify when he can log on, so no more worrying about him sneaking down in the middle of the night. I'm pretty sure I could have done this via group policy before, but I like that it's now an easy to find option.

So, I got this thing all configured and then I noticed that I didn't have the ability to "switch user" anymore. What was odd is that it was working just fine. I have no idea what caused it to go away since I was doing so many thing (it's a new install after all). After hunting around I finally found a group policy option that fixed the problem. 

1. Hold down your Windows key and press 'R' to open the Run Command box.
2. Type 'gpedit.msc' and press enter. This open Group Policy Management.
3. Navigate to Local Computer Policy/Computer Configuration/Administrative Templates/System/Logon
4. Within the Logon folder, you will see "Hide Entry Points for Fast User Switching". Right-click on it and select Edit.
5. Change the setting to "Enabled" and then press OK.
6. Close the Local Group Policy Editor
7. Hold down your Windows key and press 'R' to open the Run Command box.
8. Type 'gpupdate /force' and press enter, then wait for the black box to go away. Or you can reboot.

That's it.