Creating new script from output - powershell

Hoping this will be an easy one for somebody, but I just don't have the experience. I'm pulling the mapped network drive info from a PC. I'm testing the path to make sure it's active and that the person still has access. The test works fine. Here's my issue...
If the test is $true, I want it to output a line of code to a new .ps1 file for remapping the drive. I think I'm just about there, but I can't wrap my head around outputting a line of code and not the output of the line. Thanks for any help!
foreach ($Drive IN $Drives)
{
$MND = $Network.OpenSubKey("$Drive")
$Share = $MND.GetValue("RemotePath")
$Path = Test-Path "$Share\*"
IF ($Path -eq $true)
{
$ErrorActionPreference = "SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path C:\output.ps1 -append
"New-PSDrive -Name "$Drive" -PSProvider FileSystem -Root "$Share" -Persist"
Stop-Transcript
}
}

Per your comment, you probably don't want to be using Start-Transcript (as you'd get a lot of header content that you don't want), but rather something that outputs to a file like Out-File -Append or Add-Content.
You also need to remove the internal double quotes which are likely unnecessary (or you could replace them with single quotes):
"New-PSDrive -Name $Drive -PSProvider FileSystem -Root $Share -Persist" | Add-Content c:\output.ps1
It's worth also checking you have rights to write files to the root of C:\, this is blocked by default for non-admins in later versions of Windows.

Related

Powershell script searching files on domain

Very new to powershell and AD, so apologies if this post has an obvious answer. I have done some research and I am still not finding the answers I am looking for. My script is below for reference.
I have created a simple powershell script that will run on an admin vm i have setup on my domain. I have a separate SQL vm running a backup script that consume a lot of storage over time. I am trying to run this very simple script. My question is, do I need to modify this script in order to store it on my admin vm but have it run on my sql vm? Or can i leave the path as is and just set up in AD task scheduler. I have tried targeting the FQDN and the IP, but it doesn't seem to be working either way.
$backups_file = 'E:\blahBlahBla\SQL\Backups' or
$backups_file = '<IP_ADDRESS>\E:\blahBlahBla\SQL\Backups' or
$backups_file = '<FQDN>E:\blahBlahBla\SQL\Backups'
$backup_file_exist = (Test-Path -Path $backups_file)
if ($backup_file_exist){
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $backups_file
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $backups_file -Recurse | Where-Object {($_.LastWriteTime -lt (Get-
Date).AddDays(-7))} | Remove-Item
}
else
{
Write-Output -InputObject "Unable to access this directory."
}
Thanks.
well all your $backups_file solutions seems wrong to me.
If you want excess a directory on a Remote system, it has to be at least a fileshare or a administrative share like \\computer\e$\folder\folder\
But why using file shares or something like that when you just simple can connect to a Powershell Session on the Remote Host? here is a example.:
$mySQLServer = "Server1.domain.name", "server2.domain.name"
$backupFolder = "E:\blahBlahBla\SQL\Backups"
foreach ($server in $mySQLServer)
{
$session = New-PSSession -ComputerName $server #maybe -cred if needed
Invoke-Command -Session $session -ArgumentList $backupFolder -ScriptBlock {
param(
$directoy
)
if ($backup_file_exist)
{
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $directoy
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $directoy -Recurse | Where-Object { ($_.LastWriteTime -lt (Get-Date).AddDays(-7))
} | Remove-Item
}
}
Remove-PSSession
}
Good Luck!

Using variables within quotes in a script to map network drives

We're logging network drive mappings to a log file on our laptops. And I wanna make a script that takes these log files and maps the logged drives for the user.
Example log script:
K: -> \\server01\folder
Y: -> \\server02\publicfolder
I already have a partial script, but it looks like it doesn't work.
$logfile | foreach {
$log = $_ -split ' -> '
# Write-Host $log[0]
# Write-Host $log[1]
$Networkpath = $log[1]
$DriveLetter = $log[0] -replace ":*",""
New-PSDrive -Name `"$($DriveLetter)`" -PSProvider FileSystem -Root `"$($Networkpath)`" -Persist -Scope Global
}
When I run the above script, I'm getting errors "New-PSDrive : When you use the Persist parameter, the root must be a file system location on a remote computer.".
I'm assuming that this is because the quotes around the $DriveLetter and $Networkpath variables aren't handled correctly.
But I'm not sure how to do it properly. Been trying multiple solutions from Google, but none seem to work :(

Accessing USB stick without drive letter

I am using powershell 2.0 in windows 7.
I would like to copy a file from my USB stick to a directory on my main hard drive using cmd or powershell. However, I need this to function on any PC without any input of the USB's current drive letter. In case that didn't make sense, let me rephrase it. I need a powershell or cmd command/ batch script to copy a file from my USB stick to my hard drive without any input.
Ideal command would assign the variable mydrive to the drive letter and allow me to run something like this in cmd
copy myvar:/path/fileToCopy.txt/ C:/path/of/target/directory/
I would really appreciate if I could use just my USB sticks name ('DD') to copy like this:
copy DD:/path/fileToCopy.txt/ C:/path/of/target/directory/
I've done well over an hours worth of research trying to find a way to pull this off and can't. Any help is greatly appreciated. Especially if it is clear how to use it. I am very new to powershell and cmd commands and don't understand the syntax. So stuff like [put drive name here] to show me how to use it would be amazing and is where a lot of forums are missing out.
You can do this like below:
$destination = 'C:\path\of\target\directory'
$sourceFile = 'path\fileToCopy.txt' # the path to the file without drive letter
# get (an array of) USB disk drives currently connected to the pc
$wmiQuery1 = 'ASSOCIATORS OF {{Win32_DiskDrive.DeviceID="{0}"}} WHERE AssocClass = Win32_DiskDriveToDiskPartition'
$wmiQuery2 = 'ASSOCIATORS OF {{Win32_DiskPartition.DeviceID="{0}"}} WHERE AssocClass = Win32_LogicalDiskToPartition'
$usb = Get-WmiObject Win32_Diskdrive | Where-Object { $_.InterfaceType -eq 'USB' } |
ForEach-Object {
Get-WmiObject -Query ($wmiQuery1 -f $_.DeviceID.Replace('\','\\')) #'# double-up the backslash(es)
} |
ForEach-Object {
Get-WmiObject -Query ($wmiQuery2 -f $_.DeviceID)
}
# loop through these disk(s) and test if the file to copy is on it
$usb | ForEach-Object {
# join the DeviceID (like 'H:') with the file path you need to copy
$file = Join-Path -Path $_.DeviceID -ChildPath $sourceFile
if (Test-Path -Path $file -PathType Leaf) {
Copy-Item -Path $file -Destination $destination
break # exit the loop because you're done
}
}
Hope that helps
If you upgrade your version of PowerShell, you can replace the Get-WmiObject with Get-CimInstance for better performance. See this and that

Powershell script to install a specific program. Script works but is there a better way to do everything?

Okay so the script below is originally made using Batch and i converted it to PS. It works at the moment but is there better way to do this?
First we want to check is operating system 32 or 64 bit so we'll get the right installation path. Then we want to check is there old installation folder or not and if there is, the script should stop.
If there isn't that old installation folder, we'll create one and then import the registry file.
After that, we want to change drive H: to C:\Temp and then we'll install the msi-file. When the msi-file is installed, we want to check the installation path is the "program.exe" in the right place.
If everything is ok, we want to create folder for the GCTI files and then copy all the necessary files.
At the end of the script there's couple more file copying left and then we are done.
At the moment this script is in the same folder as the necessary installation files and when we use this to install the program, we need to copy the folder to the remote computer. I am planning to change this script a bit so that at first it asks on which computer we want to install this and then it copies all the files to the specific remote computer and then runs this script in remote computer.
#Let's check is OS 32 or 64 bit
$bit = "C:\Windows\syswow64\."
$isit64bit = Test-Path $bit
If ($isit64bit -eq $True) {$installpath = "C:\Program Files (x86)"}
Else {$installpath = "C:\Program Files"}
#Let's check is there old installation folder
$Program = $installpath+"\Program\"
$Programtest = Test-Path $Program
If ($Programtest -eq $false ) {Write-Host "None found, let's continue the installation"}
Else {Write-Host "Old installation folder found, remove files and try again" Exit}
# Create ODBC-connection in registry
Start-Process -FilePath Reg -ArgumentList import, ".\Progserver_ODBC.reg" -Wait -WindowStyle Minimized
#Let's check if previous action is ok
$registry = "HKLM:\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\Progserver\"
$registrycheck = Test-Path $registry
If ($registrycheck -eq $True) {Write-Host "Registrychange is ok"}
Else {Write-Host "Registrychange failed" Exit}
# Rename Drive "H:" C:\temp
New-PSDrive -Name "H" -PSProvider 'FileSystem' -Root C:\temp
# Install the msi
Start-Process -FilePath msiexec -ArgumentList /i, "Program-4.3.32.msi", /quiet -Wait
$install = "C:\Program Files (x86)\PathtoProgram.exe"
$installcheck = Test-Path $install
If ($installcheck -eq $True) {Write-Host "Installation succeeded"}
Else {Write-Host "Installation failed." Exit}
# Create GCTI's
$GCTI = "$installpath\PathToGCTI\"
If (Test-Path $GCTI) {Write-Host "GCTI folder already exists"}
Else {Write-Host "Create GCTI folder"} New-Item -ItemType Directory -Path $GCTI -Force
Copy-Item .\PathtoGCTI\* -Destination $GCTI -Recurse -Force
Write-Host "Copied GCTI-files"
# Copy program.ini ja vec.ini
Write-Host "Copying program.ini ja vec.ini"
Copy-Item .\PathToProgram.ini $installpath\PathToProgram.ini
Copy-Item .\PathToVec.ini $installpath\PathToVec.ini
# Change folder rights for the installation folder
cacls.exe $installpath\Program /T /E /G "All Users:C"
# Copy files from version 4.3.26
Copy-Item .\PathToProgram.exe $installpath\PathToProgram -Force
# Copy files
Copy-Item .\PathToFiles\* $installpath\PathToProgram\ -Force -Recurse
Set-ItemProperty $installpath\PathToProgram\graph\* -Name isreadonly $true
#Remove PSDrive
Remove-PSDrive -Name "H"
This is by no means exhaustive; just a selection of comments. You might be better submitting this to the Code Review StackExchange site.
General rules:
always used named parameters in PS functions
Your code formatting is important (carriage returns, tabbing/spacing, etc.)
e.g.
### Don't do this
Get-ChildItem "C:\temp"
### Instead do this
Get-ChildItem -Path "C:\temp"
Test if we're running a 64 bit OS and pick the appropriate Program Files folder
if ([environment]::Is64BitOperatingSystem) {
$installationPath = $env:ProgramFiles
}
else {
$installationPath = ${env:ProgramFiles(x86)}
}
When joining file paths, use Join-Path:
### So don't do this
$Program = $installpath+"\Program\"
### Instead do this
$Program = Join-Path -Path $installpath -ChildPath "Program"
When mapping your drive; be careful about scoping.
And probably best ensure you clean up after yourself, too! I have fallen foul of this in the past and it was a nightmare to clean up :-S
try {
if (Test-Path -Path "H:\") {
Remove-PSDrive -Name "H"
}
New-PSDrive -Name "H" -Root "C:\temp" -PSProvider FileSystem -Scope Script
### do your other stuff
catch {
throw $_.Exception
}
finally {
if (Test-Path -Path "H:\") {
Remove-PSDrive -Name "H"
}
}
Note the defensive programming (check if the drive exists already and remove it if it does!).
For bonus points you could pull the mapping code in to a separate function to avoid repetition (D.R.Y.)
Phew... I think that will do for now!
Good work :-)

Robocopy commands to copy a file to over 50 remote machines

I started looking at robocopy yesterday to try to copy and overwrite a file from one destination to many remote computers. I've tried Robocopy to copy files to a remote machine but it doesn't work. I get the same error as the person in the link. Does anybody have any suggestions or lead me in the right way ? thank you so much !
You could just use PowerShell for this. It has an inefficiency issue wherein it would copy one at a time but that shouldnt be an issue for 50ish machines. This could help if you made a PowerShell script
$computers = Get-Content "C:\filewithcomputers.txt"
$fileToCopy = "C:\filetocopy.txt"
ForEach($computer in $Computers){
Copy-Item -Path $fileToCopy -Destination "\\$computer\C`$\Temp"
}
The would copy the file $fileToCopy to each server in the file C:\filewithcomputers.txt assuming that the file contained a list of computer with each one on its own line. The file would be copied to the temp folder on each machine. Update the paths as required for your scenario. I only suggest this since you tagged powershell-remoting. If you are not adept with PowerShell maybe someone else can give you a better answer more of what you are looking for. Using RoboCopy for one file seemed tedious.
If you wanted to check to see if a folder exists and is accessible you could do something like this.
$computers = Get-Content "C:\filewithcomputers.txt"
$fileToCopy = "C:\filetocopy.txt"
ForEach($computer in $Computers){
$destinationx86 = "\\$computer\C`$\Program Files (x86)"
$destination = "\\$computer\C`$\Program Files"
If(Test-Path $destinationx86){
# Copy this to Program Files (x86)
Copy-Item -Path $fileToCopy -Destination $destinationx86
} Else {
# Copy this to Program Files
Copy-Item -Path $fileToCopy -Destination $destination
}
}
If you need to connect with different credentials, you can use
$credential = Get-Credential
New-PSDrive -Name "Computer01" -PSProvider FileSystem -Root "\\Computer01\Share" -Credential $credential -Scope global
Now you can copy to e.g. Computer01:\Folder01\
If you have set your environment up to support PSRemoting and have placed the file in a file share you can use PowerShell Remoting to instruct many computers to retrieve the file themselves nearly simultaneously with Invoke-Command. You can limit the number of simultaneous actions using -ThrottleLimit depending on the size of the source file and how robust the network/server are:
$computers = Get-Content "C:\filewithcomputers.txt"
$originalsource = "\\fileserver\shared\payload.exe"
$originaldestination = "c:\"
$scriptblockcontent = {
param($source,$destination)
Copy-Item -Path $source -Destination $destination
}
Invoke-Command –ComputerName $Computers –ScriptBlock $scriptblockcontent `
–ThrottleLimit 50 -ArgumentList $originalsource,$originaldestination