Following on from the post where I wrote about managing the entries in the PATH environment variable to avoid OS and application misbehaviour, I thought I'd share another story on PATH which can also show you why we (IT guys) should never forget the basics and that the simplest idea is the best idea!
I've come across some hosts where the PATH was more than 2048 characters long which made applications stop working. OK, no problem (I thought), I just run my script which removes duplicates from the PATH and it should go well under 2048 characters. I'm not an overconfident guy, but I was surprised when I saw the length still well above 2000. Now what? Then it hit me, why do I take it for granted that all these entries in the PATH are needed? Maybe there are PATH entries which don't even exist on the file system anymore! Simple, isn't it, just get rid of garbage from the environment variable.
Let's run through the PATH entries one by one and check if those folders exist on the box at all - important: if you do this on a cluster node where one of the PATH entries points to one of the clustered drives, you can incorrectly identify that folder as non existent, but in reality the folder exists, it's just on a disk which is active on another node of the cluster at that time, so be careful.
Of course we want to do this remotely:
$srv = "r2d2"
$pathString = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $srv).OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\Environment").getvalue("path")
$pathstring.split(";") | %{
$obj = "" | Select Item,Accessible
$obj.Item = $_.trim()
$obj.Accessible = test-path ("\\$srv\" + $obj.item.replace(":","$"))
$obj}
Make it shorter by creating the output object on the fly:
$srv = "r2d2"
$pathString = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $srv).OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\Environment").getvalue("path")
$pathstring.split(";") | %{
New-Object psobject -Property @{test=(test-path $_); item=$_}
} | ft item,test -auto
Or you can do it locally on a host (which makes it simpler and it can even be a oneliner:
(Get-ItemProperty "HKLM:SYSTEM\CurrentControlSet\Control\Session Manager\Environment").path.split(";") | %{new-object psobject -Property @{test=(test-path $_); item=$_}} | ft item,test -auto
This will show you something like:
You can make this a script by adding parameters, get the list of hosts from $input...etc.
t
Powershell one-liners and short scripts for real-life problems on large and complex Windows networks.
Showing posts with label powerhell. Show all posts
Showing posts with label powerhell. Show all posts
14 May, 2014
02 June, 2013
Edit scheduled task remotely - OS
The other day, I had a couple of 100 servers where I needed to edit a particular scheduled task. Fortunately or unfortunately all of them were Windows 2008 servers. Why am I saying that?
On Windows 2003, scheduled tasks are simple, there's one command or action, start time, run as credentials and some little other bits. So if you want to "edit" a task, you can just delete and recreate it with whatever change you wanted to make.
Unfortunately, on Windows 2008, it's not that simple. There are multiple triggers you can define, multiple actions a task can run...etc.:
However, fortunately, you can export a scheduled task into an xml file, which is quite cool as the xml format is easy to handle in PowerShell.
You can just edit the xml and import it back (basically recreate the whole task with all the settings defined in the xml).
A couple of key things in the script below. Connect to the remote machine and get task details:
$schedSvc = New-object -ComObject Schedule.Service
$schedSvc.connect($srv)
$schFolder = $schedSvc.GetFolder("\")
$schFolder = $schFolder.GetFolder($taskfolder)
$schedTask = $schFolder.GetTask($taskName)
$schedTask.xml | Out-File "$env:TEMP\$srv-$taskname.xml" -Force
Edit the xml and create a new file:
gc "$env:TEMP\$srv-$taskname.xml" | %{
....
.... } | Out-File "$env:TEMP\$srv-$taskname-new.xml" -Force
Recreate the scheduled task remotely (for this I use schtasks.exe for the sake of simplicity, although the COM object mentioned above could be used as well):
$res = schtasks.exe /create /S $srv /RU SYSTEM /TN "$taskfolder\$taskName" /XML "$env:TEMP\$srv-$taskname-new.xml" /F
The script has Object type output which looks like this:
The script (without log and error handling):
t
On Windows 2003, scheduled tasks are simple, there's one command or action, start time, run as credentials and some little other bits. So if you want to "edit" a task, you can just delete and recreate it with whatever change you wanted to make.
Unfortunately, on Windows 2008, it's not that simple. There are multiple triggers you can define, multiple actions a task can run...etc.:
| Scheduled Task on Windows 2008 |
However, fortunately, you can export a scheduled task into an xml file, which is quite cool as the xml format is easy to handle in PowerShell.
You can just edit the xml and import it back (basically recreate the whole task with all the settings defined in the xml).
| Easy to get xml representation of a Scheduled task in PowerShell |
A couple of key things in the script below. Connect to the remote machine and get task details:
$schedSvc = New-object -ComObject Schedule.Service
$schedSvc.connect($srv)
$schFolder = $schedSvc.GetFolder("\")
$schFolder = $schFolder.GetFolder($taskfolder)
$schedTask = $schFolder.GetTask($taskName)
$schedTask.xml | Out-File "$env:TEMP\$srv-$taskname.xml" -Force
Edit the xml and create a new file:
gc "$env:TEMP\$srv-$taskname.xml" | %{
....
.... } | Out-File "$env:TEMP\$srv-$taskname-new.xml" -Force
Recreate the scheduled task remotely (for this I use schtasks.exe for the sake of simplicity, although the COM object mentioned above could be used as well):
$res = schtasks.exe /create /S $srv /RU SYSTEM /TN "$taskfolder\$taskName" /XML "$env:TEMP\$srv-$taskname-new.xml" /F
The script has Object type output which looks like this:
ComputerName oldValue Result
------------ -------- ------
R2D2 120 OK
JARJAR 120 OK
C3PO 3456 OK
The script (without log and error handling):
param( [string] $hosts = "",
[string] $taskName = "",
[string] $taskFolder = "",
[string] $newvalue = "")
#### Collate the host list.
$hostlist = @($Input)
if ($hosts) {
if($hosts -imatch " "){
$hostsArr = @($hosts.split(" "))
$hostlist += $hostsArr
}
else{
$hostlist += $hosts
}
}
foreach($srv in $hostlist){
$script:sObject = "" | select ComputerName,oldValue,Result
$script:sObject.ComputerName = $srv
# connect to remote host and export the scheduled task to an xml
$schedSvc = New-object -ComObject Schedule.Service
$schedSvc.connect($srv)
$schFolder = $schedSvc.GetFolder("\")
$schFolder = $schFolder.GetFolder($taskfolder)
$schedTask = $schFolder.GetTask($taskName)
$schedTask.xml | Out-File "$env:TEMP\$srv-$taskname.xml" -Force
# edit the given text in the xml
if(Test-Path "$env:TEMP\$srv_$taskname.xml"){
gc "$env:TEMP\$srv-$taskname.xml" | %{
if($_ -imatch "\\myapplication.exe\."){
$script:sObject.oldValue = ([regex]::Match($_, "-parameter=\d")).Value -ireplace "-parameter=",""
$newline = $_ -ireplace "parameter=\d+", "parameter=$newvalue"
}
else{
$newline = $_
}
$newline
} | Out-File "$env:TEMP\$srv-$taskname-new.xml" -Force
# import the new task xml
$res = schtasks.exe /create /S $srv /RU SYSTEM /TN "$taskfolder\$taskName" /XML "$env:TEMP\$srv-$taskname-new.xml" /F
if($res -imatch "Success"){
$script:sObject.Result = "OK"
}
else{
$script:sObject.Result = "Could not import task $taskname"
}
}
else{
$script:sObject.Result = "Could not export task $taskname"
}
$objColl += $script:sObject
}
$objColl
t
Subscribe to:
Comments (Atom)