Files
admin/.tmp-concepts/cms-config-rewrite-pattern.md
vitya 4837fb32c8 import-stage: .wiki/concepts/ via split (temp prefix for merge into existing dir)
git-subtree-dir: .tmp-concepts
git-subtree-mainline: 98bcc37d32
git-subtree-split: c727aaa1b6
2026-05-21 13:46:51 +03:00

126 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Web.config rewrite — кодировка и connection-string patterns
type: concept
tags: [iis, webconfig, encoding, powershell, traceback]
sources: [../sources/nas-recovery-session-2026-05-18.md]
updated: 2026-05-19
---
# Web.config rewrite на Windows: encoding pitfall
## Сценарий
После cross-host миграции CMS в VM, нужно переписать connection strings (`192.168.1.10``10.0.2.2` или другой host). Делается через SSH/PowerShell `Get-Content`+`-replace`+`Set-Content`.
## Pitfall: Set-Content без -Encoding
```powershell
# WRONG — на PowerShell 5.1 пишет UTF-16 LE
(Get-Content $f -Raw) -replace 'old', 'new' | Set-Content $f -NoNewline
```
**Симптом** после этого:
- IIS возвращает `HTTP 500.19 - Internal Server Error`, "Файл конфигурации создан в неправильном формате XML", error code `0x8007000d`.
- В детале: первые строки файла показывают артефакты `????????` (UTF-16 в окне UTF-8 ожидаемой проверки).
**Корень:** PowerShell 5.1 (Windows встроенный) `Set-Content` без `-Encoding` использует **default = UTF-16 LE** (Unicode). IIS ожидает UTF-8 (BOM или без BOM).
## Правильный способ
```powershell
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
$content = Get-Content $file -Raw
$new = $content -replace 'old', 'new'
[System.IO.File]::WriteAllText($file, $new, $utf8WithBom)
```
Или, если хочется без BOM:
```powershell
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($file, $new, $utf8NoBom)
```
ASP.NET / IIS работают и с BOM, и без — но для дефолтного XML конфига Microsoft предпочитает с BOM.
### PowerShell 7+ workaround
В Core: `Set-Content -Encoding utf8` пишет UTF-8 БЕЗ BOM (отличается от PS 5!). `-Encoding utf8BOM`с BOM.
## Connection string patterns в CMS
Нашли в `MoreThenCms.WebUI/Web.config` source (development):
```xml
<add name="MoreThenCmsEntities"
connectionString="Data Source=DESKTOP-XYZ\SQLEXPRESS;Initial Catalog=MoreThenCms;
Integrated Security=True;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
```
В production (внутри OVA, после восстановления):
```xml
<add name="MoreThenCmsEntities"
connectionString="Data Source=192.168.1.10;Initial Catalog=MoreThenCms;
Integrated Security=False;User Id=snolla;
Password=fXkH4@8O%3pc;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
```
То есть в prod CMS использует **SQL login `snolla`**, не Integrated Security. Сам логин остался в `master.mdf` после восстановления — никаких дополнительных шагов не понадобилось.
## Mass-edit нескольких сайтов
Под Windows VM было 4 Web.config с одинаковым паттерном:
- `C:\inetpub\wwwroot\MoreThenCms.Web\Web.config`
- `C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config`
- `C:\stayer\stostayer.old\web.config`
- (плюс `C:\stayer\MoreThenCms.Web\` — main stostayer без 192.168.1.10 reference)
Скрипт через SSH в VM:
```powershell
$files = @(
'C:\inetpub\wwwroot\MoreThenCms.Web\Web.config',
'C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config',
'C:\stayer\stostayer.old\web.config'
)
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
foreach ($f in $files) {
$content = Get-Content $f -Raw
$new = $content -replace [regex]::Escape('192.168.1.10'), '10.0.2.2'
[System.IO.File]::WriteAllText($f, $new, $utf8WithBom)
}
# затем
iisreset
```
## Storage providers (Azure / MinIO)
В `appSettings` нашли:
```xml
<add name="azureGalleries" storageType="MoreThenCms.FileStorage.Azure.AzureCloudStorage, ...">
<settings>
<add name="connectionString"
value="DefaultEndpointsProtocol=http;AccountName=snolla;
AccountKey=<base64>" />
<add name="container" value="galleries" />
</settings>
</add>
```
Используется **Azure Storage SDK с custom endpoint**. В production endpoint указывает на **MinIO** (S3-compat но **не** Azure-compat — пользователь упомянул "не так всё" и обещал пояснить). Точная схема подключения — TBD, надо изучать `MoreThenCms.FileStorage.Azure.AzureCloudStorage` класс.
## `[regex]::Escape` для безопасной замены IP
`192.168.1.10` без escape — точки в regex matchят любой char. Лучше escape:
```powershell
$pattern = [regex]::Escape('192.168.1.10')
$new = $content -replace $pattern, '10.0.2.2'
```
Связано: [[snolla-recovery-vm]], [[traefik-on-windows-docker-desktop]].