PowerShell Sharepoint 2013 App Catalog - shell

I have created several SharePoint hosted apps. Is it possible to create bulk app catalogs because the app is created for a little 100 clients. I don't find a PowerShell command that can do it for Sharepoint office 365 site catalogs.
Is it also possible to upload bulk apps with PowerShell. Don't find much info on the web.
Maybe anyone here has some advice ?
Cheers,
Kris

it is possible to bulk upload apps to an Office 365 environment as it is for SharePoint on-premise.
The tricky part here is that you have to upload the apps to the app catalog, which is in fact a document library.
Recently I created a function using scripts from the internet. Posted the function below:
function UploadAppToCatalog
{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string]$webUrl,
[Parameter(Mandatory=$true)]
[string]$DocLibName,
[Parameter(Mandatory=$true)]
[string]$FilePath
)
Start-SPAssignment -Global
$spWeb = Get-SPWeb -Identity $webUrl
$spWeb.AllowUnsafeUpdates = $true;
$List = $spWeb.Lists[$DocLibName]
$folder = $List.RootFolder
$FileName = $FilePath.Substring($FilePath.LastIndexOf("\")+1)
$File= Get-ChildItem $FilePath
[Microsoft.SharePoint.SPFile]$spFile = $spWeb.GetFile("/" + $folder.Url + "/" + File.Name)
$flagConfirm = 'y'
if($spFile.Exists -eq $true)
{
$flagConfirm = Read-Host "File $FileName already exists in library $DocLibName, do you want to upload a new version(y/n)?"
}
if ($flagConfirm -eq 'y' -or $flagConfirm -eq 'Y')
{
$fileStream = ([System.IO.FileInfo] (Get-Item $File.FullName)).OpenRead()
#Add file
write-host -NoNewLine -f yellow "Copying file " $File.Name " to " $folder.ServerRelativeUrl "..."
[Microsoft.SharePoint.SPFile]$spFile = $folder.Files.Add($folder.Url + "/" + $File.Name, [System.IO.Stream]$fileStream, $true)
write-host -f Green "...Success!"
#Close file stream
$fileStream.Close()
write-host -NoNewLine -f yellow "Update file properties " $spFile.Name "..."
$spFile.Item["Title"] = "Document Metrics Report"
$spFile.Item.Update()
write-host -f Green "...Success!"
}
$spWeb.AllowUnsafeUpdates = $false;
Stop-SPAssignment -Global
}

Related

in powershell, copy-item and test-path are both failing silently.. is it my code, or something else...?

I frequently have to copy a single file to multiple destinations, so i'm trying to write a script to make that go faster. it seems to work fine when i'm dealing with local files, but fails without any errors when running on a file that is on a mapped network drive.
at first I was using copy-item, and I couldn't make that work, so i used robocopy. that does the trick, but if the file already exists, i have an if statement using test-path which is supposed to skip to a user input that asks if you want to overwrite.. this is not working. i should say the one that checks the folder exists is working, but the one that checks for the file name always comes back true. for now, i have it just forcing an overwrite with robocopy because most of the time that's what i'll want to do anyway.
here's what i have right now.. "K:" is the mapped network drive i'm copying to, and i'm usually copying files from another mapped network drive "T:". I also should mention i have this set up to run from the context menu in windows (7) explorer, and it passes the file path to the script via %L and $args.
any advice is appreciated. (i apologize in advance, i know it's rather rough.. This is somewhat new to me.)
$Folders = #("K:\OKKHM 800" , "K:\OKKHM 1000" , "K:\OKKHM 1002" , "K:\OKKHM 1003" , "K:\OKKHM 1004", "K:\OKKHM 1250")
$source = $args[0]
$Filename = Split-Path -Path $source -Leaf
$sourcefolder= split-path -path $source -parent
$COUNTER = 0
$successful=0
$CONFIRMATION=0
foreach($Folder in $Folders){
$newpath = $folder + "\" + $filename
WRITE-HOST $NEWPATH
if(-not(test-path -path $newpath)) {
if((test-path -path $folder)) {
WRITE-HOST 'TEST 2'
robocopy $sourcefolder $folder $filename -is -it
$successful=1
}
else{
write-host 'folder does not exist'
}
}
else {
$title = 'Existing File Will Be Overwritten'
$question = 'Are you sure you want to proceed?'
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))
$decision = $Host.UI.PromptForChoice($title, $question, $choices, 1)
if ($decision -eq 0) {
Write-Host 'confirmed'
$CONFIRMATION=1
}
else {
Write-Host 'cancelled'
$CONFIRMATION=0
}
IF ($CONFIRMATION -EQ 1) {
try {
robocopy $sourcefolder $folder $filename
$successful=1
}
catch {
throw "NO GOOD"
}
}
}
$COUNTER++
}
if ($successful -eq 1) {
WRITE-HOST 'SUMMARY: ' $COUNTER ' FILES COPIED SUCCESSFULLY.'
}
Start-Sleep 5

Folder 's"Date modified" incorrect (Windows 7)

Something very odd is going on with the "date modified" field of several folders on an exFAT external drive I have. A folder in which several files were recently added is still showing its date modified as its creation date. Even worse, another folder with recently added files is showing a date that precedes its creation date! Has anyone observed this and know what might be going on? I have checked online and found nothing useful/relevant regarding this. The same information shows up in both Explorer and in a command prompt so its not specific to Explorer
Run this PowerShell script. Close Explorer before running to avoid file-locking.
# -------------give each folder the highest modified date of it's files --------
function OneDir($dir)
{
# elaborate one folder, with given name
Set-Location -Path $dir.FullName
$maxd = Get-Date(0)
$files = Get-ChildItem -Recurse -Filter *.* | Where-Object { $_.PsIsContainer -eq $false }
for ($i=0; $i -lt $files.Count; $i++)
{
$file = $files[$i]
$cd = [datetime]($file.lastwritetime)
If ($cd -Gt $maxd)
{$maxd = $cd}
}
If ($files.Count -Gt 0)
{$dir.LastWriteTime = ($maxd)}
Write-Host ($dir.FullName) + " " + ($dir.LastWriteTime)
}
#------------------------- main ------------------------------------
$startDir = Read-Host 'Foldername to start with'
Set-Location -Path $startDir
$t = Get-ItemProperty $startDir
OneDir $t
$dirs = Get-ChildItem -Recurse -Filter *.* | Where-Object { $_.PSIsContainer }
for ($d=0; $d -lt $dirs.Count; $d++)
{
OneDir $dirs[$d]
}
Write-Host "Finished. press Enter"
cmd /c pause

How can I add the device names that were not scanned (offline etc) by a PowerShell script

Very very much a PowerShell newbie here I wanted a script to scan devices on the network and report on Local Admins. Found one out there and made some minor modifications to meet my needs - but I have one mod I cant work out how to do. Hoping someone out there will know a simple way to do it ?
The scrip below will read in a list of device names - scan them and output a dated report for all devices that are live and on-line. If the device is not accessible I get the following error on screen but nothing in the report.
I would like when it encounters an error that it writes to the report file - something along the lines of "$computor was not accessible!"
The code I am using is
$date = Get-Date -Format o | foreach {$_ -replace ":", "."}
ECHO "Starting scan"
$Result = #()
foreach($server in (gc .\servers.txt)){
$computer = [ADSI](”WinNT://” + $server + “,computer”)
$Group = $computer.psbase.children.find(”Administrators”)
$Filename = "c:\" + "LocalAdminAudit" + $date + ".txt"
function getAdmins
{
ECHO "SEARCHING FOR DEVICE"
$members = ($Group.psbase.invoke(”Members”) | %
{$_.GetType().InvokeMember(”Adspath”, ‘GetProperty’, $null, $_, $null)}) -
replace ('WinNT://DOMAIN/' + $server + '/'), '' -replace ('WinNT://DOMAIN/',
'DOMAIN\') -replace ('WinNT://', '')
$members}
ECHO "READY TO WRITE OUTPUT"
$Result += Write-Output "SERVER: $server"
$Result += Write-Output ' '
$Result += ( getAdmins )
$Result += Write-Output '____________________________'
$Result += Write-Output ' '
ECHO "Record written"
}
# Added date run to report
$result += Write-Output "Date Reported: $date"
$Result > $Filename
Invoke-Item $Filename
# replace "DOMAIN" with the domain name.
ECHO "Scan Complete"
And the on screen error when a machine is off line or otherwise doesn't respond is
Exception calling "Find" with "1" argument(s): "The network path was not found.
"
At \server\users\User.Name\Powershell Scripts\Get-Local-AdminsV3.ps1:1
0 char:40
+ $Group = $computer.psbase.children.find <<<< (”Administrators”)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
I would like when it encounters an error that it writes to the report file - something along the lines of "$computor was not accessible!" - I am pretty sure there must be an easy way of doing this - but I cant work it out so any tips would be greatly appreciated
As Matt, mentioned in the comments. You can use a Try/Catch block inside your function to catch the error.
I also made some other changes. The most major is that I changed the function to contain all of the code necessary to get the local administrator group. Then the loop just calls the function once per computer with the computer name. This function is then reusable.
Secondly rather than output to a text file, I changed to outputting to a CSV as is a more structured format that can be used better later.
Also rather than relying on writing to the console host, I used Write-Progress to report the progress of the loop.
$Servers = Get-Content .\servers.txt
$ExportFileName = "c:\LocalAdminAudit$date.csv"
function Get-LocalAdministrator {
[cmdletbinding()]
Param(
$ComputerName
)
$Group = [ADSI]("WinNT://$computername/Administrators,group")
try {
$Group.Invoke("Members") | ForEach-Object {
$User = ($_.GetType().InvokeMember("Adspath", 'GetProperty', $null, $_, $null) -split '/')[-2,-1] -join '\'
[PSCustomObject]#{
"User" = $User
"Server" = $ComputerName
"Date" = Get-Date -Format o | ForEach-Object {$_ -replace ":", "."}
}
}
}
catch {
[PSCustomObject]#{
"User" = "Failed to Report"
"Server" = $ComputerName
"Date" = Get-Date -Format o | ForEach-Object {$_ -replace ":", "."}
}
}
}
$LocalAdmins = foreach ($Server in $Servers) {
Write-Progress -Activity "Retrieving Local Administrators" -Status "Checking $Server" -PercentComplete (([array]::indexof($Servers,$Server)/($Server.count))*100)
Get-LocalAdministrator $Server
}
$LocalAdmins | Export-CSV $ExportFileName -NoTypeInformation
Invoke-Item $ExportFileName
Lastly, be careful of smart quotes especially when cutting and pasting between Outlook and word.

ftp batch file script

Hoping someone can guide me / help me.
The issue, I have 2 servers one running a Ubuntu which has a website for clients to login and download / view reports. The other is a windows server 2012 R2 which creates / stores the reports. I need to move the files from the windows to the Ubuntu server so clients can view. The data is large currently 7gb and growing at 3 gb a year.
I need a batch file to connect using ftp and then copy the folder to a local folder. However it only needs to copy those files which have modified.
I have only ever written one batch file and I cant seem to find any ftp batch scripts which only copies modifed files.
Your my last resort as I cant seem to find a coder who knows batch script (its a dieing art). I have never used powershell so would not know where to start here.
Any help or advice please let me know.
Thanks
John
You can do it with PowerShell with winscp. Exemple :
try
{
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "example.com"
UserName = "user"
Password = "mypassword"
SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Upload files
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
$transferResult = $session.PutFiles("d:\toupload\*", "/home/user/", $False, $transferOptions)
# Throw on any error
$transferResult.Check()
# Print results
foreach ($transfer in $transferResult.Transfers)
{
Write-Host ("Upload of {0} succeeded" -f $transfer.FileName)
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch [Exception]
{
Write-Host ("Error: {0}" -f $_.Exception.Message)
exit 1
}
This would be a way to do it in PowerShell. It would take files that are older then 31 days and upload them.
function FTP-Upload {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Source_File,
[Parameter(Mandatory=$true)]
[string]$Target_File,
[Parameter(Mandatory=$true)]
[string]$Target_Server,
[Parameter(Mandatory=$true)]
[string]$Target_Username,
[Parameter(Mandatory=$true)]
[string]$Target_Password
)
$FTP = [System.Net.FTPWebRequest]::Create("ftp://$Target_Server/$Target_File")
$FTP = [System.Net.FTPWebRequest]$FTP
$FTP.Method = [System.Net.WebRequestMethods+Ftp]::UploadFile
$FTP.Credentials = New-Object System.Net.NetworkCredential($Target_Username,$Target_Password)
$FTP.UseBinary = $true
$FTP.UsePassive = $true
# read in the file to upload as a byte array
$content = [System.IO.File]::ReadAllBytes($Source_File)
$FTP.ContentLength = $content.Length
# get the request stream, and write the bytes into it
$rs = $FTP.GetRequestStream()
$rs.Write($content, 0, $content.Length)
# be sure to clean up after ourselves
$rs.Close()
$rs.Dispose()
}
$Upload_Server = "server.network.tld"
$Upload_Location = "/data/"
$Upload_Username = "ftpuser"
$Upload_Password = "ftppassword"
$Files_To_Upload = Get-ChildItem E:\Path\To\Files -Recurse | Where-Object {($_.CreationTime -le (Get-Date).AddDays(-31)) -and (!$_.PSIsContainer)}
Foreach ($File in $Files_To_Upload) {
FTP-Upload -Source_File $File.FullName -Target_File ($Upload_Location + $File.Name) -Target_Server $Upload_Server -Target_Username $Upload_Username -Target_Password $Upload_Password
}

How can I set up continuous deployment for a SharePoint 2010 Visual Studio solution?

I want to automatically build .wsp packages and re-deploy them on a staging server after each commit. I know how to setup CruiseControl.Net for continuous integration, but I don't know how to build and deploy the packages. So far I got MSBuild to generate .wsp files , but I am struggling with a automatic re-deployment script. What I got so far is a PowerShell script:
param([string]$siteUrl = "http://machine.local")
$ErrorActionPreference = "Stop"
function WaitForPendingJob
{param ($sol)
$counter = 1
$sleeptime = 2
$safeguard = 100
while( $sol.JobExists -and ( $counter -lt $safeguard ) ) {
Write-Host -f yellow -NoNewLine "."
sleep $sleeptime
$counter++
}
Write-Host ""
}
function InstallOrUpdateSolution
{param ($SolutionWsp, $SiteUrl, $featureGuid)
$FullPath = resolve-path $SolutionWsp
$farm = Get-SPFarm
$sol = $farm.Solutions[$solutionWsp]
if ($sol)
{
Write-Host -f Green "Going to uninstall $SolutionWsp"
if( $sol.Deployed -eq $TRUE )
{
Write-Host -f Green "Deactivating feature $featureGuid at $SiteUrl"
Disable-SPFeature -Identity $featureGuid -Url $SiteUrl -Confirm:$false -force -ErrorAction Continue
Uninstall-SPSolution -Identity $SolutionWsp -WebApplication $SiteUrl -Confirm:$false -ErrorAction Continue
Write-Host -f yellow -NoNewLine "waiting for retraction"
WaitForPendingJob $sol
}
Write-Host -f Green "$SolutionWsp is retracted."
Write-Host -f Green "Going to Remove $SolutionWsp"
Remove-SPSolution -Identity $SolutionWsp -Force -Confirm:$false -ErrorAction Continue
Write-Host -f Green $SolutionWsp is deleted from this Farm
}
Add-SPSolution -LiteralPath $FullPath
Install-SPSolution -Identity $SolutionWsp -WebApplication $SiteUrl -GACDeployment -CASPolicies -Force
$sol = $farm.Solutions[$SolutionWsp]
if ($sol.Deployed -eq $false ) {
write-host -f yellow -NoNewLine "waiting for deployment"
WaitForPendingJob $sol
}
Write-Host -f Green $SolutionWsp deployed $sol.Deployed
Write-Host -f Green "Activating feature $SolutionWsp at $SiteUrl"
Enable-SPFeature -Identity $featureGuid -Url $SiteUrl
}
function RestartTimer
{
Write-Host -f Green Restarting OWSTIMER instances on Farm
$farm = Get-SPFarm
$farm.TimerService.Instances | foreach {$_.Stop();$_.Start();}
}
$date = Get-Date
Write-Host -f Green "Starting upgrade at " $date
Add-PsSnapin "Microsoft.SharePoint.PowerShell" -ErrorAction SilentlyContinue
InstallOrUpdateSolution "Solution1.wsp" $siteUrl "2c6ffaf7-84df-465c-be55-8136926d3e02"
InstallOrUpdateSolution "Solution2.wsp" $siteUrl "0c6be7af-cccd-4ccd-9b61-deffd16f7830"
InstallOrUpdateSolution "Solution3.wsp" $siteUrl "8f4862d3-94ea-467b-bdeb-2352295e08c3"
RestartTimer
$date = Get-Date
Write-Host -f Green "Upgrade finished at" $date
This breaks with seemingly random errors, while the deployment from Visual Studio 2010 works every time. How can I deploy the .wsp's from command line in a fail-proof way like the Visual Studio does it?
Why don't you just use Update-SPSolution instead of retract-delete-install-deploy sequence?
First of all, why are you over-complicating the deployment process by using PowerShell instead of stsadm in a batch file? Is there a need for PowerShell?

Resources