Wednesday, December 20, 2017

Remove iislogs

Built a nice script to remove older files from IISLogs.
It has two retentionmodes. Either clear based on number of last changed files or for specific days.

$scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
Import-Module "$($scriptPath)\XssIisTools.psm1" -Force
#$logPaths = "D:\LOGS\IIS\W3SVC2000719483","D:\LOGS\IIS\W3SVC184136160","D:\LOGS\IIS\W3SVC1417816532" #variant1 only selected folders
$logPaths = Get-ChildItem -Path "D:\LOGS\IIS\" |where-object {$_.PSIsContainer} |select -ExpandProperty FullName #variant2 all subfolders folders in selected path
$filetypes = "u_ex*.log" #what files to delete
$numerOfFileToKeep = 30
$logFileName = "LastRunLog.txt"
$logFilePath = Join-Path -Path $scriptPath -ChildPath $logFileName
Start-Transcript -Path $logFilePath
foreach ($logPath in $logPaths) {
remove-IISLogs -logPath $logpath -fileTypes $filetypes -count $numerOfFileToKeep
}
remove-IISLogs -logPath "D:\LOGS\ELMAH\App_Data" -fileTypes "*.xml" -retentionMode Days -count 30
Stop-Transcript
<#
.Synopsis
Removes files of type $filetypes from folder $logpath
.DESCRIPTION
author: xxx
created:2016-01-02
lastModified:2017-11-14
.EXAMPLE
remove-IISLogs -logPath "D:\Utils\loggTest\W3SVC442871005" -fileTypes u_ex*.log
.EXAMPLE
remove-IISLogs -logPath "D:\Utils\loggTest\W3SVC442871005" -fileTypes *.xml -retentionMode Days
#>
function remove-IISLogs {
[CmdletBinding(SupportsShouldProcess=$true,confirmImpact="Medium")]
Param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
$logPath,
$fileTypes = "*.log",
[ValidateSet("Days","Files")]
$retentionMode = "Files",
$count = 7
)
Process {
if (Test-Path -Path $logPath) {
$AllFiles = Get-ChildItem -Path $logpath -Filter $filetypes
if ($AllFiles -ne $null -and -$allfiles.count -ne 0) {
if ($retentionMode -eq "Files") {
write-verbose "Using files as retentionMode"
$oldFiles = $allfiles |Sort-Object lastWriteTime -Descending|select -Skip $count
}
elseif ($retentionMode -eq "Days") {
write-verbose "Using days as retentionmode"
$oldFiles = $AllFiles| where-object { $_.LastWriteTime -lt (get-date).AddDays(-$count)}
}
else { write-output "OldFiles couldn't be numbered" }
if ($OldFiles.count -gt 0 -and $oldFiles -ne $null) {
try {
if ($PSCmdlet.ShouldProcess("$logPath (filetypes:$filetypes) with retentionMode $retentionMode, count $count")) {
$oldFiles |Remove-Item
} #end of whatif
write-output "$($oldFiles.count) Files removed in $logPath"
}
catch {write-output "Couldn't remove..." }
}
else { write-warning "No files found (of $($allFiles.count)) matching $($fileTypes) in $logPath" }
} #end total files found check
else { write-warning "No files found in directory matching $($filetypes)" }
}
else { write-warning "Path not found :> $($logpath)" }
} #end of process
} #end of function

Thursday, November 23, 2017

Installing workflow manager on sharepoint 2016

Scenario:
Sharepoint 2016 needs workflow supports since 2010 workflows now seems dead.
This needs to be done offline

Overview of steps

  1. Download all programs from internet-enabled client with getOfflinePackages
  2. Install packages on server in correct order
  3.  Configure workflow manager
  4.  Register workflow service in sharepoint

Step 1 - Download necessary files for offlineinstallationen

On client with webaccess
  1. Install WebPlattformInstaller
  2. Download packages with getOfflinePackages.ps1
  3. $products = "ServiceBus,ServiceBusCU1,WorkflowCU4,WorkflowManagerRefresh,WorkflowClientCU4"
    $scriptPath = $(split-path -Parent $MyInvocation.MyCommand.Definition)
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/offline /products:$($products) /path:$scriptPath\WebPlattFormFiles" -NoNewWindow -PassThru -wait

Step 2 - Install packages on server in correct order

  1. Install packages with InstallWFM.ps1 to get correct order
    $scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
    #1 servicebus
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/install /products:ServiceBus /xml:$($scriptPath)\WebPlattFormFiles\feeds\latest\webproductlist.xml /AcceptEula /suppressPostFinish" -wait -passthru
    #2 service bus updates
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/install /products:ServiceBusCU1 /xml:$($scriptPath)\WebPlattFormFiles\feeds\latest\webproductlist.xml /AcceptEula /suppressPostFinish"
    #3 workflowmanager client
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/install /products:WorkflowClientCU4 /xml:$($scriptPath)\WebPlattFormFiles\feeds\latest\webproductlist.xml /AcceptEula /suppressPostFinish"
    #4 workflowmanagerrefresh
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/install /products:WorkflowManagerRefresh /xml:$($scriptPath)\WebPlattFormFiles\installers\WorkflowManagerRefresh\feeds\latest\webproductlist.xml /AcceptEula /suppressPostFinish"
    #5 workflowmanager updates
    start-process -FilePath 'C:\Program Files\Microsoft\Web Platform Installer\webpicmd.exe' -ArgumentList "/install /products:WorkflowCU4 /xml:$($scriptPath)\WebPlattFormFiles\feeds\latest\webproductlist.xml /AcceptEula /suppressPostFinish"
    view raw InstallWfm.ps1 hosted with ❤ by GitHub

Step 3 - Configure Workflow Manager

  1. Update wfmconfig.xml with credentials and databasename
  2. Configure with configureWFM.ps1
    function WFM-Configure {
    param (
    $dbServer,
    $dbPrefix,
    $spServiceAcctName,
    $spServiceAcctPwd,
    $spAdminAcct,
    $passphrase
    )
    # Create new SB Farm
    $SBCertificateAutoGenerationKey = ConvertTo-SecureString -AsPlainText -Force -String $passphrase;
    $WFCertAutoGenerationKey = ConvertTo-SecureString -AsPlainText -Force -String $passphrase;
    $managementCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_Management;Integrated Security=True;Encrypt=False';
    $gatewayCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_Gateway;Integrated Security=True;Encrypt=False';
    $messageContCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_MessageContainer;Integrated Security=True;Encrypt=False';
    Write-Host -ForegroundColor White ' - Creating new Service Bus farm...' -NoNewline;
    try {
    $sbFarm = Get-SBFarm -SBFarmDBConnectionString $managementCS;
    Write-Host -ForegroundColor White 'Already Exists';
    }
    catch {
    New-SBFarm -SBFarmDBConnectionString $managementCS -InternalPortRangeStart 9000 -TcpPort 9354 -MessageBrokerPort 9356 -RunAsAccount $spServiceAcctName -AdminGroup 'BUILTIN\Administrators' -GatewayDBConnectionString $gatewayCS -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey -MessageContainerDBConnectionString $messageContCS;
    Write-Host -ForegroundColor White 'Done';
    }
    # Create new WF Farm
    Write-Host -ForegroundColor white " - Creating new Workflow Farm..." -NoNewline;
    $wfManagementCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_Management;Integrated Security=True;Encrypt=False';
    $wfInstanceCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_InstanceManagement;Integrated Security=True;Encrypt=False';
    $wfResourceCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_ResourceManagement;Integrated Security=True;Encrypt=False';
    try {
    $wfFarm = Get-WFFarm -WFFarmDBConnectionString $wfManagementCS;
    Write-Host -ForegroundColor White 'Already Exists';
    }
    catch {
    New-WFFarm -WFFarmDBConnectionString $wfManagementCS -RunAsAccount $spServiceAcctName -AdminGroup 'BUILTIN\Administrators' -HttpsPort 12290 -HttpPort 12291 -InstanceDBConnectionString $wfInstanceCS -ResourceDBConnectionString $wfResourceCS -CertificateAutoGenerationKey $WFCertAutoGenerationKey; #changed admingroup
    Write-Host -ForegroundColor white 'Done';
    }
    # Add SB Host
    Write-Host -ForegroundColor white ' - Adding Service Bus host...' -NoNewline;
    try {
    $SBRunAsPassword = ConvertTo-SecureString -AsPlainText -Force -String $spServiceAcctPwd;
    #Add-SBHost -SBFarmDBConnectionString $managementCS -RunAsPassword $SBRunAsPassword -EnableHttpPort -EnableFirewallRules $true -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey; #removed enablehttpport
    Add-SBHost -SBFarmDBConnectionString $managementCS -RunAsPassword $SBRunAsPassword -EnableFirewallRules $true -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey;
    Write-Host -ForegroundColor white 'Done';
    }
    catch {
    Write-Host -ForegroundColor white 'Already Exists';
    #write-warning "Error was $($_.exception)"
    }
    Write-Host -ForegroundColor white ' - Creating Workflow Default Namespace...' -NoNewline;
    $sbNamespace = $dbPrefix + '-WorkflowNamespace';
    try {
    $defaultNS = Get-SBNamespace -Name $sbNamespace -ErrorAction SilentlyContinue;
    Write-Host -ForegroundColor white 'Already Exists';
    }
    catch {
    try {
    # Create new SB Namespace
    $currentUser = $env:userdomain + '\' + $env:username;
    #New-SBNamespace -Name $sbNamespace -AddressingScheme 'Path' -ManageUsers $spServiceAcctName,$spAdminAcctName,$currentUser; #replaced spAdminAcctName with spadminAcct
    New-SBNamespace -Name $sbNamespace -AddressingScheme 'Path' -ManageUsers $spServiceAcctName,$spAdminAcct,$currentUser;
    Start-Sleep -s 90
    Write-Host -ForegroundColor white 'Done';
    }
    catch [system.InvalidOperationException] {
    throw;
    }
    }
    # Get SB Client Configuration
    $SBClientConfiguration = Get-SBClientConfiguration -Namespaces $sbNamespace;
    # Add WF Host
    try {
    $WFRunAsPassword = ConvertTo-SecureString -AsPlainText -Force -String $spServiceAcctPwd;
    Write-Host -ForegroundColor White ' - Adding Workflow Host...' -NoNewline;
    Add-WFHost -WFFarmDBConnectionString $wfManagementCS `
    -RunAsPassword $WFRunAsPassword -EnableFirewallRules $true `
    -SBClientConfiguration $SBClientConfiguration -CertificateAutoGenerationKey $WFCertAutoGenerationKey;
    Write-Host -ForegroundColor White 'Done';
    }
    catch {
    Write-Host -ForegroundColor white "Already Exists";
    }
    }
    Import-Module WorkflowManager -ErrorAction SilentlyContinue
    $scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
    [xml]$wmfConfig = get-content -Path "$scriptPath\wfmConfig.xml"
    WFM-Configure -dbServer $wmfConfig.configuration.dbserver -dbPrefix $wmfConfig.configuration.dbprefix -spServiceAcctName $wmfConfig.configuration.spServiceAcctName -spServiceAcctPwd $wmfConfig.configuration.spServiceAcctPwd -spAdminAcct $wmfConfig.configuration.spAdminAcct -passphrase $wmfConfig.configuration.passphrase
    <configuration>
    <dbserver>sp2016</dbserver>
    <dbprefix>WFM</dbprefix>
    <spServiceAcctName>mycompany\workflowaccount</spServiceAcctName>
    <spServiceAcctPwd>mypassword</spServiceAcctPwd>
    <spAdminAcct>mycompany\spinstall</spAdminAcct>
    <passphrase>mypassphrase</passphrase>
    </configuration>
    view raw wfconfig.xml hosted with ❤ by GitHub
  3. Update siteaddress and run registerWFOnsite
    Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
    Import-Module WorkflowManager -ErrorAction SilentlyContinue
    Register-SPWorkflowService -SPSite "https://site.mycompany.com" -WorkflowHostUri "https://site.mycompany.com:12290"
    $wms = Get-SPWorkflowServiceApplicationProxy
    $wms.RegisterWorkflowLifecycleManagementEnvironment()
    view raw gistfile1.txt hosted with ❤ by GitHub
References:
https://www.helloitsliam.com/2014/11/06/sharepoint-2013-workflow-manager-woes/ - source for the order of installation
http://blog.robgarrett.com/2014/05/12/install-workflow-manager-with-powershell/ - original script for configuring workflow manager
https://blogs.msdn.microsoft.com/laleh/2014/09/03/sharepoint-2013-workflow-troublehsooting/ - troubleshooting workflow manager
https://social.technet.microsoft.com/wiki/contents/articles/34407.sharepoint-2016-step-by-step-installation-of-workflow-manager.aspx - another installationguide
https://knowledge.zomers.eu/SharePoint/Pages/How-to-install-and-configure-Workflow-Manager-on-Windows-2012-R2.aspx - more updated information on how to configure worklow manager
https://docs.microsoft.com/en-us/iis/install/web-platform-installer/web-platform-installer-direct-downloads - webplattforminstaller

Monday, November 20, 2017

Sharepoint and alternate languages

So what happens when a column is created and then changed.
And then, possible, changed again in an alternate language?

First created, staticName is set and the cultured name
image
When names is changed, only the culturename is changed
clip_image001
When and alternate language is added, and copy of the culturename appears.
image
When name is changed again to doktor2, only the current language version is changed. Swedish 1053.
clip_image001[6]
Now we have 3 version to manage.
When we choose overwrite language specific version the values dont change.
clip_image002
When we now change the column to Doktor3, only the 1053 version change when we’re using the alternate languagebrowser.
clip_image003
But if we change using the default language (1033) to doktor4, all local variants are overwritten
clip_image004
But then a local editor is at it again, setting doktor5 in swedish and the values are off.
clip_image005
But what happens if we now remove local variants? Then we're down to only the default columns
clip_image006
Changing from swedish gui to doktor6 and the english 1033 is changed.
clip_image007
But what happens if language is enabled again? Well, the old value is still there…
clip_image008
The lesson here?
Stay away from alternate languages!
And also a fun script for checking all the versions of a fields on a list.


Add-PSSnapin microsoft.sharepoint.powershell
$websiteUrl = "https://sharepoint.mycompany.com/sites/test2"
$listName = "LanguageList"
$web = get-spweb $websiteUrl
$cultures = $web.SupportedUICultures
$objects = @()
foreach ($culture in $cultures) {
[Threading.Thread]::CurrentThread.CurrentUICulture = $culture
write-output "Passing $($web.url) with culture $($culture.DisplayName) ($($culture.lcid))"
$list = $web.Lists[$listName]
if ($list -ne $null) {
foreach ($field in $list.Fields) {
$tempObject = new-object PSObject -Property @{staticName=$field.StaticName;culture=$culture.LCID;title=$field.Title}
$objects +=$tempObject
}
}
else {write-output "Can't find list: $listName"}
}
$objects |sort-object -Property staticName
foreach ($lang in ($objects|select culture -Unique -ExpandProperty culture)) {
write-output "Number of variants For LCID $($lang): $(($objects|where-object {$_.culture -like $lang}).count)"
}
write-output "`nSelected values:"
$objects |where-object {$_.staticName -like "Title" -or $_.staticName -like "Doktor"} |format-table

Monday, October 30, 2017

Troubleshooting sharepoint alerts

Method for determining what happens with sharepoint alerts from the serverside.


  1. To determined which server is sending the mail.
    (Note that this will be different for different webapps, so best is to monitor the whole farm with ULS)
    run Sysinternals procmon on all servers (usually only the frontends) monitor traffic for :25
  2. Activate verbose logging for alerts
    Add-PSSnapin microsoft.sharepoint.powershell
    $names = "Alerts"
    foreach ($name in $names)
    {
    Get-SPLogLevel -Identity $name
    set-sploglevel -Identity $name -TraceSeverity verbose -EventSeverity verbose #default value Tracesev High and EventSev Information
    }
    write-output "Trace levels set to verbose for"
    $names |format-table -AutoSize
  3. Monitor ULSViewer on specific member or the whole farm for events matching below
    Category contains "Alerts" AND Message contains "Alert for" OR Message contains "Successfully sent"
Now ULS messages will show successfull and failed (based on securityfiltering) sent emails.

References:
https://blogs.technet.microsoft.com/steve_chen/alerts-in-sharepoint-troubleshooting-mosswss/
http://sharepointalert.info/troubleshooting-sharepoint-alerts/
http://www.sharepointdiary.com/2012/02/sharepoint-alerts-not-working-troubleshooting-checklist.html

Sunday, October 01, 2017

Openhab2 with telldus tellstick duo

The complete steps to get up and running with a raspberry3, openhab2 and telldus tellstick for managing lights.

  1. Install sdcard with image openhabian using win32 diskimager 
  2. Logon raspberry with openhabian:openhabian using putty
  3. Set new password with passwd
  4. Set static ip
    1. sudo nano /etc/dhcpcd.conf  (insert your own ip)
      interface eth0
      static ip_address=192.168.0.10/24
      static routers=192.168.0.1
      static domain_name_servers=192.168.0.1
  5. Update software
    1. sudo apt-get update 
    2. sudo apt-get upgrade
  6. Goto yourip:8080 , and choose standardpackage.
  7. Start a new sitemap.config  for example default.sitemap in /etc/openhab2/sitemapsEasiest way to open explorer and go to \openhab-confsitemap default1 label="Main menu" {
     Frame {
             Text label="Information" {
             Text item=Cpu_Load label="System load"              
           }
    Text label="Inställningar" icon="office" {
    Switch item=Scene5                                      
    }
     }
    }
    End example
  8. Telldus support
    1. Add to /etc/apt/sources.list
      deb
      http://download.telldus.com/debian/ stable main
    2. Add public key
      wget -q
      http://download.telldus.se/debian/telldus-public.key -O- | sudo apt-key add -
    3. Update repository
      sudo apt-get update
    4. Install telldus-core
      sudo apt-get install telldus-core
    5. Add devices in /etc/tellstick.conf  . Se example belowdevice {
                              id = 3
                              name = "Vardagsrum:rodlampa"
                              controller = 0
                              protocol = "arctech"
                              model="selflearning-switch"
                              parameters {
                              house="7778459"
                              unit="3"
                             }
                          }
  1. Train your devices with tdtool --learn 3 (where 3 is deviceID)
    Unplug nexadevice and run command, when system blinks its connected.
  2. Restart telldus services
    sudo /etc/init.d/telldusd restart - starta om telldus tjänster
  3. Install Tellstick bindings in paperUI
  4. Add all things that show up
  5. Create item from each things switchchannel and add to sitemap
  1. install bindings Weatherinfo for local temperatures and weather
    1. Install Eclipse IoT marketplace under Addons>bindings>misc
    2. Install weatherunderground
    3. Configure thing with location key (that you get att weatherunderground) and location. Works best with bigcitys like Sweden/Gotenburg
  2. To allow for js-scripts.
    1. Install JS transform
    2. Install RegEx Transformation
    3. Put scripts in /transform-folder
  3. To allow execs (running bash or commands like restart)
    1. Install exec-binding
  4. To get systeminfo stuff like cpuload
    1. Install binding SystemInfo
    2. Associate things with items
    3. Add items to sitemap
  5. To get sunstate
    1. Install Astro bindings
    2. Add things with your location as position.
    3. Create items that you link on sitemap
    4. Set category to good icons , like Moon
    5. To get phases to show, use formatting in label" [MAP(astro.map):%s]"
  6. To format dates in sitemap
    1. Show only hours, add to label [%1$tH:%1$tM]
      Example label="Soluppgång [%1$tH:%1$tM]"

Wednesday, September 27, 2017

Patching Sharepoint with the homebrew-method

Patchning Sharepoint is not something to taken lightly.
It's a high risk not to patch but a guaranteed risk to apply the patches.

Last year I had a difficult experience when I patched a semilarge(7 members) farm for the first time with Cumulative Updates.
This had 5 webapplications and +200 databases. And it took some time. Like 30 hours, most of the time being lost when running psconfig on each host.
Supposedly, sharepoint should only upgrade the databases on the first member run, but something still takes a lot of time, even its only to check if upgrade is required.

So a more effective method was needed.
I looked into the impressive SPPatchify-project but found the results to be too inconsistent. Sometimes the script ran through it all and said everything was green, when actually two servers had failed psconfigs and a lot of other issues giving half-finished state.
So I deviced my own hybrid method using the best parts of the sppatchify-idea and russmax exe-installationscript.

The method took the installationwindow down to 4 hours in total, where only 2 hours was complete downtime.
Its a bit more manual than others, but therefore also gives more control.

The steps
Preperations

  1. Take whole farm offline and take snapshots, or use regular backups. Whichever method you trust most.
  2. Backup All databases
Installation
  1. Stop all sharepointrelated-services
    1.  For AppServers 1. App-Prepatching
    2.  For Frontends  1. WFE-PrePatching
  2. Run exe on all members
  3. Start all services 
    1. For AppServers 2. App-PostPatching
    2. For frontends  2. WFE-PostPatching
  4. Export all databasinformation to file.
    1. ExportAllDbs.ps1
  5. Dismount all databases (after making sure you have all correct info on file from previousStep) This will take everything offline.
    1. DismountAllDbs.ps1
  6. Run psconfig on all members starting with AppServers
    1. RunPSConfig.ps1 on each member 
  7. Mount all databases
    1. MountAllDbs.ps1  - Update the filename to your exported databases
  8. Upgrade databases in parallel. While each db is upgrading website on it will be unavailable. If you're sql supports it you can mitigate this using -usesnapshot  How many concurrent jobs is depending on hardware. I found the sweetspot to be 4 concurrent jobs, after that it started taking longer time that running them in sequence. But this might vary. 
    1. UpgradeDatabasesFaster.ps1
  9. Check on warnings in Health Analyzer, make repairs if needed. 
  10. Make sure User Profile Synchronizer service is running (if your using FIM-sync)


Below all relevant scripts. Use at your own risk.
Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue
$starttime = Get-Date
########################
##Stop Search Services##
########################
##Checking Search services##
$srchctr = 1
$srch4srvctr = 1
$srch5srvctr = 1
$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"
If(($srv4.status -eq "Running") -or ($srv5.status-eq "Running"))
{
# Write-Host "Choose 1 to Pause Search Service Application" -ForegroundColor Cyan
# Write-Host "Choose 2 to leave Search Service Application running" -ForegroundColor Cyan
# $searchappresult = Read-Host "Press 1 or 2 and hit enter"
Write-Host
# if($searchappresult -eq 1)
# {
$srchctr = 2
Write-Host "Pausing the Search Service Application" -foregroundcolor yellow
Write-Host "This could take a few minutes" -ForegroundColor Yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.pause()
# }
# elseif($searchappresult -eq 2)
# {
# Write-Host "Continuing without pausing the Search Service Application"
# }
# else
# {
# Write-Host "Run the script again and choose option 1 or 2" -ForegroundColor Red
# Write-Host "Exiting Script" -ForegroundColor Red
# Return
# }
}
Write-Host "Stopping Search Services if they are running" -foregroundcolor yellow
if($srv4.status -eq "Running")
{
$srch4srvctr = 2
set-service -Name "OSearch15" -startuptype Disabled
$srv4.stop()
}
if($srv5.status -eq "Running")
{
$srch5srvctr = 2
Set-service "SPSearchHostController" -startuptype Disabled
$srv5.stop()
}
do
{
$srv6 = get-service "SPSearchHostController"
if($srv6.status -eq "Stopped")
{
$yes = 1
}
Start-Sleep -seconds 10
}
until ($yes -eq 1)
Write-Host "Search Services are stopped" -foregroundcolor Green
Write-Host
#######################
##Stop Other Services##
#######################
Set-Service -Name "IISADMIN" -startuptype Disabled
Set-Service -Name "SPTimerV4" -startuptype Disabled
Write-Host "Gracefully stopping IIS W3WP Processes" -foregroundcolor yellow
Write-Host
iisreset -stop -noforce
Write-Host "Stopping Services" -foregroundcolor yellow
Write-Host
$srv2 = get-service "SPTimerV4"
if($srv2.status -eq "Running")
{$srv2.stop()}
Write-Host "Services are Stopped" -ForegroundColor Green
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
$starttime = Get-Date
Add-PSSnapin microsoft.sharepoint.powershell
#######################
##Stop Other Services##
#######################
Set-Service -Name "IISADMIN" -startuptype Disabled
Set-Service -Name "SPTimerV4" -startuptype Disabled
Write-Host "Gracefully stopping IIS W3WP Processes" -foregroundcolor yellow
Write-Host
iisreset -stop -noforce
Write-Host "Stopping Services" -foregroundcolor yellow
Write-Host
$srv2 = get-service "SPTimerV4"
if($srv2.status -eq "Running")
{$srv2.stop()}
#stop distcache
write-host -foregroundcolor yellow "Stopping Distributed Cache Service gracefully..."
Stop-SPDistributedCacheServiceInstance -graceful
write-host -foregroundcolor red "Distributed Cache is stopped."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
write-host -foregroundcolor Yellow "Status of Distributed Cache Services = "$instance.status
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
Add-PSSnapin Microsoft.SharePoint.Powershell
$starttime = Get-Date
##################
##Start Services##
##################
Write-Host "Starting Services Backup" -foregroundcolor yellow
Set-Service -Name "SPTimerV4" -startuptype Automatic
Set-Service -Name "IISADMIN" -startuptype Automatic
##Grabbing local server and starting services##
$servername = hostname
$server = get-spserver $servername
$srv2 = get-service "SPTimerV4"
$srv2.start()
$srv3 = get-service "IISADMIN"
$srv3.start()
$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"
###Starting Search Services###
set-service -Name "OSearch15" -startuptype Automatic
$srv4.start()
Set-service "SPSearchHostController" -startuptype Automatic
$srv5.start()
###Resuming Search Service Application###
Write-Host "Resuming the Search Service Application" -foregroundcolor yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.resume()
#distcache
write-host -foregroundcolor green "Starting service .."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
$instance.provision()
write-output "Distributed Cache has status: $($instance.status)"
Write-Host "Services are Started" -foregroundcolor green
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Add-PSSnapin microsoft.sharepoint.powershell
$starttime = Get-Date
##################
##Start Services##
##################
Write-Host "Starting Services Backup" -foregroundcolor yellow
Set-Service -Name "SPTimerV4" -startuptype Automatic
Set-Service -Name "IISADMIN" -startuptype Automatic
##Grabbing local server and starting services##
$servername = hostname
$server = get-spserver $servername
$srv2 = get-service "SPTimerV4"
$srv2.start()
$srv3 = get-service "IISADMIN"
$srv3.start()
#$srv4 = get-service "OSearch15"
#$srv5 = get-service "SPSearchHostController"
###Starting Search Services###
#set-service -Name "OSearch15" -startuptype Automatic
#$srv4.start()
#Set-service "SPSearchHostController" -startuptype Automatic
#$srv5.start()
###Resuming Search Service Application###
#Write-Host "Resuming the Search Service Application" -foregroundcolor yellow
#$ssa = get-spenterprisesearchserviceapplication
#$ssa.resume()
write-output "Starting service .."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
$instance.provision()
write-output "Distributed Cache has status: $($instance.status)"
Write-output "Services are Started"
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
$fileName = "Databases_$(get-date -format 'yyMMdd_HHmm')"
$object = @()
foreach ($db in $alldbs) {
$tempObj = [pscustomobject]@{name=$db.name;webapplication=$db.webapplication.url;databaseserver=$db.normalizeddatasource }
$object += $tempObj
}
$object |export-csv -Path "$($scriptPath)\$($fileName).csv"
write-output "Exported $($alldbs.count) databases to file"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$startTime = get-date
write-host "script started at $($startTime)"
foreach ($db in $alldbs) {
write-output "Dismounting $($db.name)"
Dismount-SPContentDatabase $db.name -Confirm:$false
}
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
$startTime = get-date
write-host "script started at $($startTime)"
push-location "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\bin"
.\psconfig.exe -cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources -cmd services -install
Pop-Location
$endtime = get-date
write-host "Done in $(($endtime-$starttime).TotalMinutes) minutes"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
$fileName = "Databases_170530_1301.csv"
$collection = import-csv -path "$($scriptPath)\$($fileName)"
$startTime = get-date
write-host "script started at $($startTime)"
foreach ($db in $collection) {
try {
Mount-SPContentDatabase -Name $db.name -WebApplication $db.WebApplication -DatabaseServer $db.databaseserver
}
catch {write-output "error: $($_.exception)" }
}
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalminutes) minutes"
#created: 2017-05-30
#lastModified: 2017-05-30
#description: starts powershell jobs to run $numberofConcurrent at the same time
add-pssnapin microsoft.sharepoint.powershell
$numberofConcurrentJobs = 4
$jobName = "UpgradeDbs"
$collection = get-spcontentdatabase |where-object {$_.needsupgrade -eq $true}
$counterJobs = 0
if ($collection.count -ne 0 -or $collection -ne $null) {
$startTime = get-date
write-host "script started at $($startTime)"
write-output "Found $($collection.count) databases to upgrade"
foreach ($item in $collection) {
#argone has to be a string value. no objects allowed.
$argOne = $item.name
start-job -name "$($jobName)_$($argOne)" -ScriptBlock {
$internalString = $args[0]
#where action happens
Add-PSSnapin microsoft.sharepoint.powershell
try {
Upgrade-SPContentDatabase $internalString -Confirm:$false -erroraction stop | out-null
}
catch { write-warning "Error: $internalString : $($_.exception)" }
} -ArgumentList $argOne
$counterJobs++
#check numberof running jobs, wait until new one can be started
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
while ($jobs.count -ge $numberofConcurrentJobs) {
write-output "Waiting for jobs.... at count: $($jobs.count) (started $counterJobs so far) "
start-sleep 5
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
}
}
#wait for all jobs to be completed
while ($jobs.count -gt 0) {
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
write-output "Waiting for all jobs to clear... $($jobs.count) left"
if ($jobs.count -gt 0) {start-sleep 15}
}
#get results from all jobs
get-job |where-object {$_.name -like "$jobName*"} |receive-job -AutoRemoveJob -wait
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalminutes) minutes ($(($endtime-$starttime).totalseconds) seconds)"
}
else { write-output "Couldnt find any databases needing upgrade" }

Add-PSSnapin Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue
$starttime = Get-Date
########################
##Stop Search Services##
########################
##Checking Search services##
$srchctr = 1
$srch4srvctr = 1
$srch5srvctr = 1
$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"
If(($srv4.status -eq "Running") -or ($srv5.status-eq "Running"))
{
# Write-Host "Choose 1 to Pause Search Service Application" -ForegroundColor Cyan
# Write-Host "Choose 2 to leave Search Service Application running" -ForegroundColor Cyan
# $searchappresult = Read-Host "Press 1 or 2 and hit enter"
Write-Host
# if($searchappresult -eq 1)
# {
$srchctr = 2
Write-Host "Pausing the Search Service Application" -foregroundcolor yellow
Write-Host "This could take a few minutes" -ForegroundColor Yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.pause()
# }
# elseif($searchappresult -eq 2)
# {
# Write-Host "Continuing without pausing the Search Service Application"
# }
# else
# {
# Write-Host "Run the script again and choose option 1 or 2" -ForegroundColor Red
# Write-Host "Exiting Script" -ForegroundColor Red
# Return
# }
}
Write-Host "Stopping Search Services if they are running" -foregroundcolor yellow
if($srv4.status -eq "Running")
{
$srch4srvctr = 2
set-service -Name "OSearch15" -startuptype Disabled
$srv4.stop()
}
if($srv5.status -eq "Running")
{
$srch5srvctr = 2
Set-service "SPSearchHostController" -startuptype Disabled
$srv5.stop()
}
do
{
$srv6 = get-service "SPSearchHostController"
if($srv6.status -eq "Stopped")
{
$yes = 1
}
Start-Sleep -seconds 10
}
until ($yes -eq 1)
Write-Host "Search Services are stopped" -foregroundcolor Green
Write-Host
#######################
##Stop Other Services##
#######################
Set-Service -Name "IISADMIN" -startuptype Disabled
Set-Service -Name "SPTimerV4" -startuptype Disabled
Write-Host "Gracefully stopping IIS W3WP Processes" -foregroundcolor yellow
Write-Host
iisreset -stop -noforce
Write-Host "Stopping Services" -foregroundcolor yellow
Write-Host
$srv2 = get-service "SPTimerV4"
if($srv2.status -eq "Running")
{$srv2.stop()}
Write-Host "Services are Stopped" -ForegroundColor Green
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
$starttime = Get-Date
Add-PSSnapin microsoft.sharepoint.powershell
#######################
##Stop Other Services##
#######################
Set-Service -Name "IISADMIN" -startuptype Disabled
Set-Service -Name "SPTimerV4" -startuptype Disabled
Write-Host "Gracefully stopping IIS W3WP Processes" -foregroundcolor yellow
Write-Host
iisreset -stop -noforce
Write-Host "Stopping Services" -foregroundcolor yellow
Write-Host
$srv2 = get-service "SPTimerV4"
if($srv2.status -eq "Running")
{$srv2.stop()}
#stop distcache
write-host -foregroundcolor yellow "Stopping Distributed Cache Service gracefully..."
Stop-SPDistributedCacheServiceInstance -graceful
write-host -foregroundcolor red "Distributed Cache is stopped."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
write-host -foregroundcolor Yellow "Status of Distributed Cache Services = "$instance.status
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
Add-PSSnapin Microsoft.SharePoint.Powershell
$starttime = Get-Date
##################
##Start Services##
##################
Write-Host "Starting Services Backup" -foregroundcolor yellow
Set-Service -Name "SPTimerV4" -startuptype Automatic
Set-Service -Name "IISADMIN" -startuptype Automatic
##Grabbing local server and starting services##
$servername = hostname
$server = get-spserver $servername
$srv2 = get-service "SPTimerV4"
$srv2.start()
$srv3 = get-service "IISADMIN"
$srv3.start()
$srv4 = get-service "OSearch15"
$srv5 = get-service "SPSearchHostController"
###Starting Search Services###
set-service -Name "OSearch15" -startuptype Automatic
$srv4.start()
Set-service "SPSearchHostController" -startuptype Automatic
$srv5.start()
###Resuming Search Service Application###
Write-Host "Resuming the Search Service Application" -foregroundcolor yellow
$ssa = get-spenterprisesearchserviceapplication
$ssa.resume()
#distcache
write-host -foregroundcolor green "Starting service .."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
$instance.provision()
write-output "Distributed Cache has status: $($instance.status)"
Write-Host "Services are Started" -foregroundcolor green
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Add-PSSnapin microsoft.sharepoint.powershell
$starttime = Get-Date
##################
##Start Services##
##################
Write-Host "Starting Services Backup" -foregroundcolor yellow
Set-Service -Name "SPTimerV4" -startuptype Automatic
Set-Service -Name "IISADMIN" -startuptype Automatic
##Grabbing local server and starting services##
$servername = hostname
$server = get-spserver $servername
$srv2 = get-service "SPTimerV4"
$srv2.start()
$srv3 = get-service "IISADMIN"
$srv3.start()
#$srv4 = get-service "OSearch15"
#$srv5 = get-service "SPSearchHostController"
###Starting Search Services###
#set-service -Name "OSearch15" -startuptype Automatic
#$srv4.start()
#Set-service "SPSearchHostController" -startuptype Automatic
#$srv5.start()
###Resuming Search Service Application###
#Write-Host "Resuming the Search Service Application" -foregroundcolor yellow
#$ssa = get-spenterprisesearchserviceapplication
#$ssa.resume()
write-output "Starting service .."
$instance = get-spserviceinstance |where-object {$_.typename -eq "Distributed Cache" -and $_.Server.Name -eq $env:computername}
$instance.provision()
write-output "Distributed Cache has status: $($instance.status)"
Write-output "Services are Started"
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
Write-Host "Script Complete"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
$fileName = "Databases_$(get-date -format 'yyMMdd_HHmm')"
$object = @()
foreach ($db in $alldbs) {
$tempObj = [pscustomobject]@{name=$db.name;webapplication=$db.webapplication.url;databaseserver=$db.normalizeddatasource }
$object += $tempObj
}
$object |export-csv -Path "$($scriptPath)\$($fileName).csv"
write-output "Exported $($alldbs.count) databases to file"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$startTime = get-date
write-host "script started at $($startTime)"
foreach ($db in $alldbs) {
write-output "Dismounting $($db.name)"
Dismount-SPContentDatabase $db.name -Confirm:$false
}
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalseconds) seconds"
$startTime = get-date
write-host "script started at $($startTime)"
push-location "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\bin"
.\psconfig.exe -cmd upgrade -inplace b2b -wait -cmd applicationcontent -install -cmd installfeatures -cmd secureresources -cmd services -install
Pop-Location
$endtime = get-date
write-host "Done in $(($endtime-$starttime).TotalMinutes) minutes"
Add-PSSnapin microsoft.sharepoint.powershell
$alldbs = get-spcontentdatabase
$scriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
$fileName = "Databases_170530_1301.csv"
$collection = import-csv -path "$($scriptPath)\$($fileName)"
$startTime = get-date
write-host "script started at $($startTime)"
foreach ($db in $collection) {
try {
Mount-SPContentDatabase -Name $db.name -WebApplication $db.WebApplication -DatabaseServer $db.databaseserver
}
catch {write-output "error: $($_.exception)" }
}
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalminutes) minutes"
#created: 2017-05-30
#lastModified: 2017-05-30
#description: starts powershell jobs to run $numberofConcurrent at the same time
add-pssnapin microsoft.sharepoint.powershell
$numberofConcurrentJobs = 4
$jobName = "UpgradeDbs"
$collection = get-spcontentdatabase |where-object {$_.needsupgrade -eq $true}
$counterJobs = 0
if ($collection.count -ne 0 -or $collection -ne $null) {
$startTime = get-date
write-host "script started at $($startTime)"
write-output "Found $($collection.count) databases to upgrade"
foreach ($item in $collection) {
#argone has to be a string value. no objects allowed.
$argOne = $item.name
start-job -name "$($jobName)_$($argOne)" -ScriptBlock {
$internalString = $args[0]
#where action happens
Add-PSSnapin microsoft.sharepoint.powershell
try {
Upgrade-SPContentDatabase $internalString -Confirm:$false -erroraction stop | out-null
}
catch { write-warning "Error: $internalString : $($_.exception)" }
} -ArgumentList $argOne
$counterJobs++
#check numberof running jobs, wait until new one can be started
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
while ($jobs.count -ge $numberofConcurrentJobs) {
write-output "Waiting for jobs.... at count: $($jobs.count) (started $counterJobs so far) "
start-sleep 5
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
}
}
#wait for all jobs to be completed
while ($jobs.count -gt 0) {
$jobs = get-job |Where-Object {$_.name -like "$jobName*" -and $_.state -like "Running"}
write-output "Waiting for all jobs to clear... $($jobs.count) left"
if ($jobs.count -gt 0) {start-sleep 15}
}
#get results from all jobs
get-job |where-object {$_.name -like "$jobName*"} |receive-job -AutoRemoveJob -wait
$endtime = get-date
write-host "Done in $(($endtime-$starttime).totalminutes) minutes ($(($endtime-$starttime).totalseconds) seconds)"
}
else { write-output "Couldnt find any databases needing upgrade" }


References:
https://blogs.msdn.microsoft.com/russmax/2013/04/01/why-sharepoint-2013-cumulative-update-takes-5-hours-to-install/ - Russmax excellent script for halting services before running exe. Saving hours
http://www.spjeff.com/2016/05/16/sppatchify-cu-patch-entire-farm-from-one-script/ - SpJeffs
https://blogs.technet.microsoft.com/stefan_gossner/2015/08/20/why-i-prefer-psconfigui-exe-over-psconfig-exe/ - Excellent resource for patching

Monday, March 20, 2017

Users break dispform

In this particular case a user decided to throw away the main webpart of the dispform.aspx. This caused all kinds of problems since it was a calenderlist.
In this situationen it wasn’t possible to create a new list since a lot of coded things worked with listids. Theres no versioning of dispform.
I first tried to use restore to sitedefinitions, but this kind of change didn’t qualify for making restore for some reason.
So this what came instead.

1. Find a functioning “vanilla” dispform.aspx from a list of same type
2. Open Sharepoint Designer, goto website of above list, find list and copy ListID
3. Find dispform of functioning list and export to file. Save locally on computer
4. Open locally saved dispform with notepad. Find and replace listid of sourcelist with targetlist listID (in calenderar two matches)
5. Opensharepint Designer, goto website of broken list.
6. All Files>Lists><mylist>
7. Take a backup of dispform with export to file, just in case you mess up.
8. Import locally modified dispform
9. Changes take effect immediatly.

References:
https://support.microsoft.com/en-hk/help/2000858/listview-webpart-required-on-dispform.aspx-page-for-document-library

Powershell and Uptimerobot

Uptimerobot can be quite tedious when you need to update many monitors at once. For example say you bought the license for Uptimerobot and n...