I have the below PowerShell script which I want to run from command prompt but it gives me Cannot find the path error for files ServerList.txt and Urls.txt. Script works when I change directory to the folder where the script and files exists.
write-host "********* Changing IE Settings********************"
$servers = Get-Content .\ServerList.txt
$Urls = Get-Content .\Urls.txt
$command ={
$registryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\InternetSettings\ZoneMap\Domains"
Foreach ($url in $Urls)
{
$checkRegistryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\" + $url
if(!(Test-Path $checkRegistryPath))
{
write-host "Adding url to local intranet"
if($url -eq "localhost")
{
$key = (get-item HKCU:\).OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains", $true)
$subkey=$key.CreateSubKey('localhost')
$subkey.SetValue("http","1","DWORD")
$subkey.SetValue("https","1","DWORD")
$key.Close()
$subkey.Close()
}
elseif($url -like '*system*')
{
$key = (get-item HKCU:\).OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains", $true)
$subkey = $key.CreateSubKey('//system')
$subkey.SetValue("hcp","1","DWORD")
$key.Close()
$subkey.Close()
}
elseif($url -like '*next.loc*')
{
$key = (get-item HKCU:\).OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains", $true)
$key.CreateSubKey("next.loc")
$serverkey =(get-item HKCU:\).OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\next.loc", $true)
$servername= (([System.Uri]$url).Host).split('.')
$subkey=$serverkey.CreateSubKey($servername[0])
$subkey.SetValue("http","1","DWORD")
$key.Close()
$serverkey.Close()
$subkey.close()
}
}
else
{
write-host $url "url already added to local intranet"
}
}
}
Foreach ($server in $servers)
{
if([string]::IsNullOrEmpty($server))
{
Invoke-Command -ScriptBlock $command
}
else
{
Invoke-Command -Computer $server -ScriptBlock $command
}
}
write-host "****** IE Settings Changed Sucessfully************"
You can determine the path of your script using:
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
Now you can use the $scriptPath to combine your path using the Join-Path cmdlet:
$servers = Get-Content (Join-Path $scriptPath 'ServerList.txt')
$Urls = Get-Content (Join-Path $scriptPath 'Urls.txt')
Related
I am trying to remove vulnerable classes from the log4j jar file with powershell.
I am able to remove the file using the script locally on the server, however, I want to remove the class from many paths on many servers and trying to use invoke-command.
The script can open and read the JAR file but doesnt seem to action the delete() method. Is there a way to get powershell to delete the class "remotely"?
Here is my script:
$servers = #(
"server"
)
$class_to_delete = "JMSSink"
$unable_to_connect = #()
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.Filesystem
write-host "`nTesting connection to:" -ForegroundColor Yellow
$servers | ForEach-Object {Write-Host "$_"}
$servers | ForEach-Object {
$server = $_
try {
write-host "`nTesting $($server)"
Invoke-Command -ComputerName $server -ScriptBlock {
Write-Host "Connection successful to $($env:computername)" -ForegroundColor Green
} -ErrorAction Stop
} catch {
write-host "`nConnection failed to $($server)"
$unable_to_connect += $server
}
}
Write-Host "`nStarting script to remove $($class_to_delete) class from log4j" -ForegroundColor Yellow
$objects_skipped = #()
$servers | ForEach-Object {
$server_node = $_
write-host "`nPut in the file paths for $($server_node)" -ForegroundColor Yellow
$file_locations = (#(While($l=(Read-Host).Trim()){$l}) -join("`n"))
$file_locations | Out-File C:\temp\output.txt #Change this path to the temp folder and file on the server you execute from
$file_objects = Get-Content -Path C:\temp\output.txt #Change this path to the temp folder and file on the server you execute from
$stats_x = foreach ($file_object in $file_objects) {
$stats = Invoke-Command -ComputerName $server_node -ScriptBlock {
Write-Host "`nStarting on $($env:COMPUTERNAME)"
$class = $using:class_to_delete
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.Filesystem
$ful_path = $using:file_object
$fn = Resolve-Path $ful_path
try {
$zip = [System.io.Compression.ZipFile]::Open("$fn", "Read")
Write-Host "Backing up $($fn) to $($fn).bak"
$zip.Dispose()
Copy-Item "$fn" "$($fn).bak"
$zip = [System.io.Compression.ZipFile]::Open($fn, "Update")
$files = $zip.Entries | Where-Object { $_.name -eq "$($class).class" }
if (!$files) {
write-host "`nNo $($class) class found on $($env:COMPUTERNAME) for path: $($ful_path)"
$files.dispose()
$not_found = #()
$not_found += New-Object -TypeName PSObject -Property #{
Server = $env:COMPUTERNAME;
Path = $ful_path;
Result = "$($class) class NOT FOUND"
}
Write-Output $not_found
} else {
foreach ($file in $files) {
write-host "`n$($class) class found on $($env:COMPUTERNAME) for path: $($ful_path)"
write-host "`nDeleting file $($file)" -ForegroundColor Green
#delete class
$file.delete()
#check if class was successfully deleted
$confirm_delete = $zip.Entries | Where-Object { $_.name -eq "$($class).class" }
write-host $confirm_delete
if ($confirm_delete.name -match "$class.class") {
$deleted_status = "$($class) !!NOT REMOVED!!"
} else {
$deleted_status = "$($class) REMOVED"
}
$Output = #()
$Output += New-Object -TypeName PSObject -Property #{
Server = $env:COMPUTERNAME;
Path = $ful_path;
Result = $deleted_status
}
Write-Output $Output
}
}
} catch {
Write-Host "Cannot open $($ful_path) as a Zip File. $($Error[0])"
}
}
Write-Output $stats
}
$objects_skipped += $stats_x
}
#result
write-host "`nEnd result"
$objects_skipped | select Server,Result,Path | ft -AutoSize
You need to explicitly call Dispose() on the containing archive to persist the updates to the file on disk:
# this goes immediately after the `catch` block:
finally {
if($zip -is [IDisposable]){ $zip.Dispose() }
}
By placing the call to $zip.Dispose() inside a finally block, we ensure that it's always disposed regardless of whether an exception was thrown in the preceding try block.
i have trouble with "New-PSDrive -Root"
When i try to map a New-PSDrive -Root $patch with a $path using an array, the cmd does not map the drive but give me an error : "The network Path was not found".
The path is working if i use an explorer in my windows.
How can i fix that ?
Thanks a lot
exemple :
foreach ($s in $serverlist)
{
$path = "\\$s\e$\Updates\file\
New-PSDrive -Name "S" -Root $path -Persist -PSProvider "FileSystem" -Credential $cred
}
Problem
This is the entire script :
Get-Date -Format "dddd MM/dd/yyyy HH:mm K">> "C:\file\results.txt"
$cred = Get-Credential -Credential domain\name
$serverlist = #(get-content -Path "C:\file\serverlist.txt")
foreach ($s in $serverlist)
{
$path = "\\$s\e$\Updates\file\"
New-PSDrive -Name "S" -Root $path -Persist -PSProvider "FileSystem" -Credential $cred
$path2 = "\\$s\e$\Updates\file\errors.txt"
$file = Get-Content $path2
$containsWord = $file | %{$_ -match "0"}
if ($containsWord -contains $true) {
Out-File -FilePath "C:\file\results.txt" -Append -InputObject "$s : ok"
} else {
Out-File -FilePath "C:\file\results.txt" -Append -InputObject "$s : nok"
}
Remove-PSDrive -Name "S"
}
EDIT 1 : If i try to access to the file directly by an windows explorer with the same credential and I, after that, run the script, it works
As commented, the user in $cred may have permissions to access the file in the path on the server, but you as it seems do not.
Try using Invoke-Command where you can execute a scriptblock using different credentials than your own:
$cred = Get-Credential -Credential domain\name
$serverlist = Get-Content -Path "C:\file\serverlist.txt"
# loop through the list of servers and have these perform the action in the scriptblock
$result = foreach ($s in $serverlist) {
Invoke-Command -ComputerName $s -Credential $cred -ScriptBlock {
# you're running this on the server itself, so now use the LOCAL path
$msg = if ((Get-Content 'E:\Updates\file\errors.txt' -Raw) -match '0') { 'ok' } else { 'nok' }
# output 'ok' or 'nok'
'{0} : {1}' -f $env:COMPUTERNAME, $msg
}
}
# write to the results.txt file
# change 'Add-Content' in the next line to 'Set-Content' if you want to create a new, blank file
Get-Date -Format "dddd MM/dd/yyyy HH:mm K" | Add-Content -Path 'C:\file\results.txt'
$result | Add-Content -Path 'C:\file\results.txt'
In fact, you don't even need a foreach loop because parameter -ComputerName can receive an array of server names:
$result = Invoke-Command -ComputerName $serverlist -Credential $cred -ScriptBlock {
# you're running this on the server itself, so now use the LOCAL path
$msg = if ((Get-Content 'E:\Updates\file\errors.txt' -Raw) -match '0') { 'ok' } else { 'nok' }
# output 'ok' or 'nok'
'{0} : {1}' -f $env:COMPUTERNAME, $msg
}
I have the following PowerShell script that creates a session with Windows server administrator account.I want to report in case of failure of Invoke-command the error and save it in a file
Below is the code that I wrote but if i tamper for example .json file(set a wrong username),execution fails and error_report.txt is not created
#Param(
$user = "lamda"
#)
$user_domain = (Get-WmiObject Win32_ComputerSystem).Domain
$user_computer = (Get-WmiObject Win32_ComputerSystem).Name
$file = "error_report.txt"
If ((Test-Path "creds.json") -eq $True)
{
$jsonfile = Get-ChildItem creds.json
if ($jsonfile.Length -eq 0)
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' is empty"
break
}
else
{
$creds= (Get-Content creds.json | Out-String | ConvertFrom-Json)
$admin = $creds.username
$passwd = $creds.password
if (($admin) -and ($passwd))
{
$Password = ConvertTo-SecureString -String $passwd -AsPlainText -Force
$credential = [pscredential]::new($admin,$Password)
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential
If ($command -eq $false)
{
$file = "error_report.txt"
Set-Content -Path $file -Value "Error:Session between user and server
could not be created,please check your Credentials"
}
break
}
elseif (([string]::IsNullOrEmpty($admin)) -or ([string
]::IsNullOrEmpty($passwd)))
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:One object of 'creds.json' seems
to be empty.Please check your file "
}
}
break
}
else
{
#$file = "error_report.txt"
Set-Content -Path $file -Value "Error:The file 'creds.json' does not exist"
}
I think the issue is the way you are defining the condition on your if statement.
You use -eq $false however if you connections fails it does not set the vale of command to $false it will leave command as a null as it return no value (it errorred).
What you can try is either use the null operator (!) in your if statement so:
If (!$command){Do stuff}
Or you can give you invoke command an error variable and check if that has a value when run.
$command = Invoke-Command -ComputerName Server.$user_domain -FilePath
C:\SECnology\Data\Utilities\Updating.ps1 -ArgumentList
$user,$admin,$user_computer -Credential $credential -ErrorVariable TheError
If ($TheError)
{Do stuff}
so I m having this issue with getting my results to write out to an Out-file.
The problem I m having is, if new file item does exist, the error message I m getting is saying the path is null.
Please review the script and let me know your thoughts
thanks
$sScriptVersion = "1.0"
$dir = $PSScriptRoot
$svrlist += $dir + '\' + 'serverlist.txt'
$folder = 'search'
$computername = Get-Content $svrlist
$drv_array = #()
$new_drv_array =#()
$SearchStr = "error"
$log_pth = 'ProgramData\something\something\something\logs'
$file_logs = #()
$log_pth = #()
$log_nme = #()
$srchpath = #()
foreach($server in $computername)
{
$disks = Get-WmiObject -ComputerName $server -Class Win32_LogicalDisk -Filter "DriveType = 3";
foreach($disk in $disks)
{
$drv_array += $disk.DeviceID;
}
$driv =Foreach-Object {$drv_array -replace ":", "$"}
foreach($drv in $driv)
{
$new_drv_array += '\\'+ $server + '\'+ $drv +'\'+ $log_pth
}
}
Foreach($tst_pth in $new_drv_array )
{
$dvr_testpath = test-path $tst_pth
$srchpath += $tst_pth + '\'+ "*.*"
if ($dvr_testpath -eq $false)
{
write-host "This path does not exist " $tst_pth
}
else
{
write-host "This path does exist" $tst_pth
$Sel = Select-String -pattern $SearchStr -Context 2, 3 -path $srchpath
$out_file = New-item -ErrorAction ignore -itemtype File (join-path $dir1 $log_nme)
This is the part I'm having the issues with
$tst = Test-Path $out_file
if($tst -eq $false)
{
write-host "writing out parsed log file"
if($Sel -ne $null)
{
$Sel| Out-File $out_file
}
}
else
{
write-host " parsed log file does exist"
if($Sel -ne $null)
{
$Sel| Out-File -Append $out_file
}
}
}
}
I'm trying (and failing) to:
Connect to the server by iterating through a list.
Confirm location where file exists (1 of 3 locations).
Replace a string in that file.
I've tried to do this multiple ways. There are two that I have which do part of what I want.
Can someone please help me understand if there's something I'm doing inefficiently or how to put all this together?
This one can loop through the servers and find the file
$ErrorActionPreference = 'SilentlyContinue'
$nope=$null
$servers= Get-Content C:\Servers.txt
foreach ($server in $servers)
{
If (Test-Connection -ComputerName $server -Quiet)
{Invoke-Command -ComputerName $server -ScriptBlock {$file=(Get-Childitem -Path C:\DiskSpace.ps1, D:\DiskSpace.ps1, Y:\DiskSpace.ps1); Write-Host "Found $file on $env:computername."}}
Else {
Write-Host ">> Could not connect to $server."; $nope += $server}
}
Write-Host $nope
...and this one can at least find a local file
$valid=#('')
$paths = #("C:\Users\user_name\Desktop\DiskSpace.ps1","C:\DiskSpace.ps1","D:\DiskSpace.ps1","Y:\DiskSpace.ps1")
Foreach ($path in $paths)
{
if (Test-Path $path)
{$valid += $path}
}
write-host $valid
Here's how I intend to to replace the string:
$ErrorActionPreference = 'SilentlyContinue'
$find=(Get-Childitem -Path C:\, D:\, Y:\ -include DiskSpace.ps1 -Recurse)
Write-Host $find
$ErrorActionPreference = 'Stop'
try {
(Get-Content $find).replace('bad_email#domain.com', 'good_email#domain.com') | Set-Content $find
}
catch {
}
Get-Content $find
You had all the pieces already. Simply loop over your Get-Content command for each file in the Invoke-Command.
$ErrorActionPreference = 'SilentlyContinue'
$servers = Get-Content C:\Servers.txt
$files = #('C:\DiskSpace.ps1', 'D:\DiskSpace.ps1', 'Y:\DiskSpace.ps1')
$report = foreach ($server in $servers) {
if (Test-Connection -ComputerName $server -Quiet) {
$response = Invoke-Command -ComputerName $server -ScriptBlock {
Get-Childitem -Path $using:files | ForEach-Object {
(Get-Content $_).replace('bad_email#domain.com', 'good_email#domain.com') | Set-Content $_
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "$($_.fullname) updated."
}
}
}
if ($response -eq $null) {
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "No files found"
}
} else {
$response
}
} else {
[PSCustomObject]#{
Name = $env:COMPUTERNAME
Message = "Unreachable"
}
}
}
$report