Install Printers from XML Files - powershell

I backed up printers from a Windows 10 system to XML files. I'm trying to add them using the Set-Printconfiguration CMDLET, but it seems to be not accepting variables?
I've looked everywhere but I cannot find anything saying my syntax is wrong.
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $printer -PrintTicketXml c:\temp\printers\$printer
}
Here is the code I used to get the printer XML files:
$TARGETDIR = "c:\temp\printers"
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
}
# Get all the printers:
$PN = (get-printer | select name).name
# Foreach loop to create XML file for each printer configuration
Foreach ($P in $PN){
$GPC = get-printconfiguration -PrinterName $P
mkdir c:\temp\printers\$P
$GPC.PrintTicketXML | out-file C:\Temp\printers\$P.xml
# $p|select *|out-file -Path c:\temp\$p.xml -NoTypeInformation
}
edit: here is the error I'm getting:
Set-PrintConfiguration : The specified printer was not found.
At U:\PowerShell\Scripts\backup\newRestorePrinters.ps1:15 char:9
+ Set-PrintConfiguration -PrinterName $printer -PrintTicketXml ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (MSFT_PrinterConfiguration:ROOT/StandardCi...erConfiguration) [Set-PrintConfiguration], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070709,Set-PrintConfiguration
edit
I added more variables to get the list of printers w/out the .XML on the end of the names. It still gives me the same error output. It looks like it's not passing my variables to the set-printconfiguration command?
New restore script code:
$printerShortNameList = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($shortName in $printerShortNameList)
{
$shortName.Replace('.xml', "x")
}
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $shortName -PrintTicketXml c:\temp\printers\$printer
}

What was the error message? Shouldn't you take the '.xml' off the end of $printer for the printer name? I think you have to use add-printer first. I don't believe Set-PrintConfiguration creates printers.
On the bottom when you make the xml files, why do you create the c:\temp\printers\$p directory?

Set-PrintConfiguration:
You need administrator credentials to use Set-PrintConfiguration.

Related

Get-Content error when passing variable as path - Powershell Script

I have the following script.
#Script publicador
$carpetas = Get-ChildItem -Directory -Path C:\Publicaout | Sort-Object {[int]($_ -replace '(\d+).*', '$1')} | Format-Wide -Column 1 -Property Name | Out-String
foreach ($line in $carpetas.Split([string[]]"`r`n", [StringSplitOptions]::RemoveEmptyEntries))
{
$destino = Get-Content c:\Publicaout\$line\Destino.txt
echo $destino
#Copy-Item -Path C:\Publicaout\$line -Recurse -Destination C:\temp\ -ToSession $session -Force
#Invoke-Command -ComputerName $destino -Credential $cred -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'c:\temp\$Using:line\publicador.bat'"}
#Invoke-Command -ComputerName $destino -Credential $cred -ScriptBlock {Remove-Item \\$Using:destino\c$\temp\$Using:line -Recurse -Force}
}
What it does, first it sorts by numerical order subfolders on a folder called Publicaout in C:, then I get the list of those subfolders in order, and I use for each to use each element of the list as a parameter, for each one of those folders, I copy it to a remote server, and then I run a script which is located within that copied folder, after that, i delete that folder so i do not leave any leftovers.
So far so good, but now, within each folder there's a text file that contains the destination server that each specific folder must be copied to. So, I believed that adding a Get-Content + path to the file, using the $line variable that contains the subfolder name would be enough, but each time I run the script i get this error:
Get-Content : Cannot find path 'C:\Publicaout\3000\Destino.txt' because it does not exist.
At C:\Users\elmarichaladmin\Documents\publicador.ps1:18 char:14
+ $destino = Get-Content c:\Publicaout\$line\Destino.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Publicaout\3... \Destino.txt:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
This happens with each folder, i have 5 folders, named 1, 99,654,3000, 65404. Its really weird because the Copy command works perfect, but Get-Content does not.
Any ideas? I know that the errors shows an empty line, but as you can see I get rid of each empty line when i run the string split.

Powershell - Struggling to copy file from variable location

Ive been banging my head with a powershell script that i've tried a few differnt methods with and was wondering if someone can help?
Unsure at this point if im just doing something silly, thanks in advance
Aim:
To copy a vbs file from user's homedrives to a different location, the location of the vbs file changes depending on which user needs account admin doing hence why this needs to be variable. It gets the location from a text file which includes the exact path to go to and a destination which has already been created to copy the files to.
Where I have the issue currently:
$location = Get-Content C:\Users\Administrator\Desktop\here\drive4.txt | Out-String
$dest = "C:\Users\Administrator\Desktop\here"
Get-ChildItem -Path $location |
Copy-Item -Destination $dest -Recurse -Container -filter "peruser.vbs"
write-host $location
Read-Host -Prompt "Press Enter to continue or CTRL+C to quit"
The Issue
Please see the below, I have put write host to show the location powershell is trying to reach, as a side note I am able to reach this location fine through file explorer
Screenshot of error
Error Recieved
Get-ChildItem : Illegal characters in path.
At C:\Users\Administrator\Desktop\MapNetworkDrives2.ps1:17 char:1
+ Get-ChildItem -Path $location | Copy-Item -Destination $dest -Recurse -Container ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (\\WIN-7V7GI0R7C...
:String) [Get-ChildItem], ArgumentException
+ FullyQualifiedErrorId : ItemExistsArgumentError,Microsoft.PowerShell.Commands.GetChildItemCommand
Get-ChildItem : Cannot find path '\\WIN-7V7GI0R7CFK\homedrives\Onetest$
' because it does not exist.
At C:\Users\Administrator\Desktop\MapNetworkDrives2.ps1:17 char:1
+ Get-ChildItem -Path $location | Copy-Item -Destination $dest -Recurse -Container ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (\\WIN-7V7GI0R7C...
:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Unless I have misunderstood you - you are just trying to copy a file to various locations based on a list. If so you just need to loop through your list. Does this work for you?
$location = Get-Content "C:\Users\Administrator\Desktop\here\drive4.txt"
$dest = "C:\Users\Administrator\Desktop\here"
foreach ($loc in $location){
$vbs = (gci $loc -Filter "peruser.vbs").FullName
Copy-Item $vbs $dest -Force
}
You are not showing what is in the text file, forcing us to guess, which is not really a good thing relative to trying to help you. So, I am going to assume it's just a list of drive letters or path UNC's, which is really moot since you can pull those dynamically, thus no need for the file.
I don't understand why you are doing this...
Get-Content 'C:\Users\Administrator\Desktop\here\drive4.txt' |
Out-String
If it is just a text file for reading, why are you piping that anywhere?
You don't need double quotes for this. Single quotes for simple string, double for variable expansion or other specific formatted requirements
$dest = 'C:\Users\Adminstrator\Desktop\here'
Just pass the read directly
Get-Content 'C:\Users\Administrator\Desktop\here\drive4.txt' |
ForEach {
"Processing location $($PSItem.FullName)"
Copy-Item -Path $PSItem.FullName -Destination $dest -Filter 'peruser.vbs' -Recurse -WhatIf
}
Point of note:
You don't need Write-Host to output to the screen, as that is the PowerShell default, as I'll show in my example to follow. Really, except for writing screen text with color, you'd never need to use Write-Host/echo at all, well, there are a few other specific times to use it.
Also of note, regarding Write-Host from the inventor of Monad/PowerShell Jeffery Snover
http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful
https://twitter.com/jsnover/status/727902887183966208
https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Information?view=powershell-5.1
You also, do not necessarily need both Get-ChildItem and Copy-Item, since both will read the folder tree recursively. As I'll show below. I am using splatting to tighten up the code block for readability.
So, if I demo this just using a drive and folder on my system. And step through a script build out to make sure I am getting what I expect at each step before moving to the next.
Get-PSDrive -PSProvider FileSystem |
Format-Table -AutoSize
<#
# Results
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
C 357.48 118.83 FileSystem C:\ Windows\system32
D 114.10 362.71 FileSystem D:\ Scripts
E 1194.00 668.89 FileSystem E:\
F 3537.07 188.83 FileSystem F:\
G FileSystem G:\
#>
# Validate if there is any content in the destination
Try
{
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach {
"Processing location $($PSItem.Root) and the contents are as listed."
(Get-ChildItem -Path 'D:\Temp\here' -Recurse).FullName
}
}
Catch {Write-Warning -Message 'No content in the destination folder'}
<#
# Results
Processing location D:\ and the contents are as listed.
WARNING: No content in the destination folder
#>
# Show what is on the drive for the source files
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
(Get-ChildItem -Path "$($PSItem.Root)\Temp\book1.csv" -Recurse).FullName
}
<#
# Results
Processing the location D:\
D:\Temp\Source\book1.csv
D:\Temp\book1.csv
#>
<#
# Show what will happen if a Copy files from the source to the destination occurs
Using splatting for readability
#>
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
$CopyItemSplat = #{
Path = "$($PSItem.Root)\Temp\book1.csv"
Destination = "$($PSItem.Root)\Temp\here"
Recurse = $true
WhatIf = $true
}
}
Copy-Item #CopyItemSplat
<#
# Results
Processing the location D:\
What if: Performing the operation "Copy File" on target "Item: D:\Temp\book1.csv Destination: D:\Temp\here\book1.csv".
If the results are as expected, execute the action
Using splatting for readability
#>
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach{
"Processing the location $($PSItem.Root)"
$CopyItemSplat = #{
Path = "$($PSItem.Root)\Temp\book1.csv"
Destination = "$($PSItem.Root)\Temp\here"
Recurse = $true
}
}
Copy-Item #CopyItemSplat
<#
# Results
Processing the location D:\
#>
# Validate if there is any content in the destination
Try
{
Get-PSDrive -PSProvider FileSystem |
Where Name -eq 'D' |
ForEach {
"Processing location $($PSItem.Root) and the contents are as listed."
(Get-ChildItem -Path 'D:\Temp\here' -Recurse).FullName
}
}
Catch {Write-Warning -Message 'No content in the destination folder'}
<#
# Results
Processing location D:\ and the contents are as listed.
D:\Temp\here\book1.csv
#>

Piping values to New-Item to create directories in PowerShell

I've got a directory, C:\temp\test\, containing three DLL's I've called First.dll, Second.dll, Third.dll. I want to create sub-directories named after each of the DLL's.
This is what I've tried so far:
$dirName = "Tenth"
new-item $dirName -ItemType directory
That works. It created a sub-directory called "Tenth".
This also works:
(get-childitem -file).BaseName | select $_
It returns:
First
Second
Third
I've checked the type of the output from that command and it tells me "select $_" is of type System.String.
Now the bit that doesn't work:
(get-childitem -file).BaseName | new-item -Name $_ -ItemType directory
I get the following error repeated three times:
new-item : An item with the specified name C:\temp\test already exists.
At line:1 char:34
+ (get-childitem -file).BaseName | new-item -Name $_ -ItemType directory
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceExists: (C:\temp\test:String) [New-Item], IOException
+ FullyQualifiedErrorId : DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand
The current folder I'm executing the commands from is C:\temp\test\ .
I haven't been able to find any similar examples on the Internet to show me where I'm going wrong. Can anyone give me any pointers? Cheers.
Now the bit that doesn't work:
(get-childitem -file).BaseName | new-item -Name $_ -ItemType directory
This way, it works and doesn't need the ForEach-Object:
(dir -file).BaseName|ni -name{$_} -ItemType directory -WhatIf
$_ references each item as it comes along the pipeline so you will need to pipe to ForEach-Object for your line to work, like this:
(get-childitem -file).BaseName | ForEach-Object {new-item -Name $_ -ItemType directory}
This will create the item in the current powershell directory, you can also specify -Path if you want to create the folders somewhere else.
(get-childitem -file).BaseName | ForEach-Object {new-item -Name $_ -Path C:\MyFolder -ItemType directory}
New-Item accepts the parameter -Path to be piped and it can be an array of strings.
Then, you can create an object with a property Path that contains all the needed folders to be created
<#
# a simple array as example,
# but it could be the result of any enumerable,
# such as Get-ChildItem and stuff
#>
$FoldersToCreate = #('a', 'b', 'c')
# creates the folders a, b and c at the current working directory
[PSCustomObject]#{ Path = $FoldersToCreate } | New-Item -ItemType Directory
Or, alternatively :
$FoldersToCreate |
Select-Object #{ name = "Path"; expression = { "c:\testDir\$_" } } |
New-Item -ItemType Directory

Import-GPO by using folders named after its DisplayName - Powershell

I am using a powershell script to import GPOs which I have saved as GUIDs (the default).
I wish to import the GPOs on a different system, the GPOs are saved to a CD at this point. So a simple way to import a single GPO would be:
$domain=[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Name
$import_array = get-childitem ($current_drive + $gpo_backup_location) | Select name
foreach ($GPO in $import_array) {
Import-GPO |
-backupgponame $GPO.name -path ($Current_Drive + $gpo_backup_location) |
-domain $domain |
-Targetname $GPO.name |
-migrationtable ($Current_drive + $mig_table_path) |
-Createifneeded;
}
}
the $import_array command gives me my folder names
Name
----------
GPO-1
GPO-2
GPO-3
GPO-4
and so on...
I want to iterate over these and import each one. The GPOs are saved using another block of code to backup the GPOs as their displayname. (GPO-1, GPO-2, etc.,)
I cannot for the life of me figure out how to force it to look at the folder name and to import these
EDIT
The Backup was created with the following code:
Function GPO_Backup_DisplayName ($MenuChoice) {
write 'Backing Up GPOs by Display Name'
Foreach ($GPO in $GPO_Temp_Backup) {
$GPOBackup = Backup-GPO `
-name $GPO.DisplayName `
-path ($Current_drive + $GPO_Backup_Location) `
-Domain $domain;
Get-GPOReport $GPO.DisplayName `
-reporttype HTML `
-Domain $domain `
-path ($Current_drive + $GPO_Backup_HTML_Report + $GPO.DisplayName + ".html");
Rename-item
-path ($Current_drive + $GPO_Backup_Location + "{" + $GPOBackup.Id + "}") `
-newname $GPO.DisplayName
}
}
If you export each GPO to its own folder and name that folder after the GPO, you can iterate over these folders in a foreach loop to import the GPOs and set the target name to the folder name. Something like this should work:
Get-ChildItem "C:\backup" | % {
$name = $_.name
$id = (get-childitem $_) -replace '[{}]', ''
Import-GPO -BackupId $id -TargetName $name -path $_.Path -CreateIfNeeded
}
Prerequisite is that you created the backups with something like this:
Get-GPO -All | % {
$name = $_.DisplayName
$dir = New-Item "C:\backup\$name" -Type Directory
Backup-GPO -Guid $_.Id -Path $dir
}
Also, the backup directory should contain only the folders with the single GPO backups, otherwise you'll have to add a filter between Get-ChildItem and ForEach-Object.
List Group Policy Object using PowerShell

Powershell - Export Multiple CSV's into unique folders

I have been working on a PowerShell script for the better part of well a week or two. I've been able to get some parts of it working however I'm unable to fully get this automated.
I deal with a lot of CSV files on a daily basis, I have been tasked with uploading them into our software however sometimes they're too large to handle so I break them down based upon their "type" (it's a column in the CSV) and I export it to a single CSV per "type". I've been able to accomplish this with the following:
$file = gci -Filter "*.csv";
Import-Csv $file `
| Group-Object –Property “type” `
| Foreach-Object `
{
$path=$_.name+”.csv” ; $_.group `
| Export-Csv –Path $path –NoTypeInformation
}
So this works wonderfully, for each individual CSV. Unfortunately I don't have the time to do this for each individual CSV. Now I come to my other PowerShell script:
get-childitem -Filter "*.csv" `
| select-object basename `
| foreach-object{ $path=$_.basename+".csv" #iterate through files.
if(!(Test-Path -path $_.basename)) #If the folder of the file can't be found then it will attempt to create it.
{
New-Item $_.basename -type directory; $file=$_.basename+".csv";
Import-Csv $file `
| Group-Object -Property "Type" `
| Foreach-Object {
$path=$_.name+".csv"; $_.group `
| `
if(!(Test-Path -path $path2))
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
else
{
"Failed on: " + $_.basename
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
}
}
}
else
{
Import-Csv $path `
| Group-Object -Property "Type" `
| Foreach-Object {$path=$_.basename+".csv" ; $_.group
if(Test-Path -path $._)
{
New-Item $path2 -type directory
Export-Csv -Path $path2 + "\" + $path -NoTypeInformation
}
#else
#{
Write-Host "Failed on: $_.basename"
#Export-Csv -Path $_.basename + "\" + $path -NoTypeInformation
#}
}
}
}
I just can't wrap my head around "why" this isn't working effectively. I have two conditionals. Is there a folder for the CSV? If no create one. I have to have another one because one of the "types" contains a \ which errors out if I don't have the folder, so I automatically try to create it. When I run the script I get the Path is null.
The Error is:
The term ' ' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
At C:\Users\c.burkinshaw\foldermake.ps1:11 char:26
+ | ` <<<<
+ CategoryInfo : ObjectNotFound: ( :String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Test-Path : Cannot bind argument to parameter 'Path' because it is null.
At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
+ CategoryInfo : InvalidData: (:) [Test-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.TestPathCommand
Any help would be greatly appreciated, if you have questions please don't hesitate to ask.
You have not defined $path2 anywhere, so something like test-path -path $path2 will say path is null. And in one place you are using $._ which will again give errors.
Edit after question updated with error message:
Your error message also says the same
Test-Path : Cannot bind argument to parameter 'Path' because it is
null. At C:\Users\c.burkinshaw\foldermake.ps1:12 char:45
+ if(!(Test-Path -path <<<< $path2))
Also the other error is in:
$path=$_.name+".csv"; $_.group `
| `
what are you trying to do here with the $_.group?
It is not proper. You cannot do $_.group | and provide some if statement.
Other comments:
Why are using $_.basename and then appending .csv? You could have just used $_.name. Try to not use the select-object basename - I don't see the value.
Extract the common import-csv and export-csv part into a function.