I am trying to build a PowerShell script to repair damaged shortcuts on remote hosts
I am using PowerShell V 2 and PowerSE to build the script, running on a Windows 7 Enterprise SP1 and patching is up to date.
The script (RepairLinkScript.ps1), has four functions, Test-ComputerStatus, Open-Connection, Repair-Link and Main. It has two script scoped variables, $Script:Log and $Script:LogName to implement script wide logging.
Main, has one output "Repair_Link_Log_$DateTime.txt". It bulds the full path for the log and populates $Script:LogName
Test-ComputerStatus has one argument, and outputs two files. The argument supplies the hosts to be tested; it can come from the command line, a file or a variable. The function seperates the hosts into two catagories, on and off line, outputting each to a file and passing online systems to Open-Connection. At various points throughout status is input to $Script:Log, on exiting the function $Script:Log is append to the log file created in Main
Open-Connection has one argument, and one output. It calls Repair-Link from the Invoke-Command cmdlet, and outputs to the file created in Main.
Repair-Link has no arguments and one output.
Each function has been tested separately and they perform as I expect. When I pass a list of systems to Test-ComputerStatus it sorts the systems into the two groups creates the files and logs to centeral log. Repair-Link it finds and repairs the effected links on the local machine and adds to the log if that line is uncommented. Open-Connection is capable of connecting to remote hosts and using Get-Process output that to the log. The problem is when I replace Get-ChildItem with Repair-Link, the repairs are preformed but nothing is added to the log. Here are Open-Connection and Repair-Link:
functionOpen-Connection
{
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
param(
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName = $True)]
[string[]]$OnlineComputers
)
BEGIN {
Write-Verbose 'EnteringOpen-ConnectionBEGIN block'
Write-Verbose 'ExitingOpen-ConnectionBEGIN block'
}
PROCESS {
Write-Verbose 'EnteringOpen-ConnectionPROCESS block'
$Script:Log =foreach ($CompNamein$OnlineComputers)
{
if ($PSCmdlet.ShouldProcess($CompName)) {
$ses =New-PSSession -ComputerName$CompName -Name"RemoteComp"
Invoke-Command -Session$ses -ScriptBlock ${function:RepairLink}
# Invoke-Command -Session $ses -ScriptBlock {Get-Process}
}# End ShouldProcess
Get-PSSession |Remove-PSSession
}# End foreach
Write-Verbose 'ExitingOpen-ConnectionPROCESS block'
}# End PROCESS block
END {
Write-Verbose 'EnteringOpen-ConnectionEND block'
Write-Output$Script:Log
$Script:Log |Out-File$Script:LogName
Write-Verbose 'ExitingOpen-ConnectionEND block'
}
}# End Open-Connection
function RepairLink
{
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact='Low')]
param(
[string[]]$RepairLog =$null
)
BEGIN{
Write-Verbose 'Entering RepairLinkBEGIN block'
[string]$IncludeString = "*Internet Explorer*.lnk"
[string]$ExcludeString = "*(64-bit)*"
[string]$MatchString = "(x86)"
[string]$TestPath = "iexplore.exe"
[string]$x86IEPath = "C:\Program Files (x86)\Internet Explorer\iexplore.exe"
$comp =Get-ChildItem Env:ComputerName
$RepairLog+= $($comp.Value)
$Users =Get-ChildItem"C:\Users"
Write-Verbose 'Exiting RepairLinkBEGIN block'
} # End BEGIN block
PROCESS{
Write-Verbose 'Entering RepairLinkPROCESS Block'
Write-Verbose 'Entering Userforeach loop'
foreach ($Userin$Users){
$FullPath = "C:\Users\$User\AppData\Roaming\Microsoft\"
Write-Verbose 'Creating$objShell'
$objShell =New-Object -ComObjectWScript.Shell
$RepairLog+=$User
Write-Verbose 'EnteringTest-Pathif'
if (Test-Path$FullPath){
Write-Verbose 'Entering main logic'
Get-ChildItem -Path$FullPath -Include$IncludeString -Exclude$ExcludeString -Force -Recurse |
ForEach-Object{
$Link =$objShell.CreateShortcut($_.FullName)
$Target = $($_.Name)
if($Link.TargetPath-match$MatchString)
{
$RepairLog+= "`t$Target = $($Link.TargetPath.ToString())"
} # End if
elseif ($Link.TargetPath-match$TestPath)
{
$RepairLog+= "$Target = $($Link.TargetPath.ToString())"
$Link.TargetPath =$x86IEPath
$Link.Save()
$RepairLog+= "`t$Target = $($Link.TargetPath.ToString())"
} # End elseif
} # End ForEach-Object
Write-Verbose 'Exiting main logic'
Write-Verbose 'ExitingTest-Pathif'
} # End if
Write-Verbose 'Exiting Userforeach block'
} # End foreach
Write-Verbose 'Exiting RepairLinkPROCESS block'
}# End PROCESS Block
END
{
Write-Verbose 'EnteringEND block'
# $Script:Log = $RepairLog
# $Script:Log | Out-File $Script:LogName
Write-Verbose 'ExitingEND block'
} # End END block
}# End RepairLink
I have tried adding arguments to Invoke-Command, using jobs and others.
Thanks